本文利用java自带的socket编程实现了一个简单的静态资源服务器,能够响应静态资源。本文一共有两个版本的源码。第一个版本名为Server_v1,该版本实现了一个简单的socket的服务器,帮助读者回忆socket编程。第二个版本名为Server_v2,该版本是对初版的改良,给出了改良思路,作出了必要的封装,让其可以响应css、html、jpg等静态资源。css
该版本实现一个简单的socket服务器,针对浏览器的请求,可以返回相应的页面。
其源码以下:html
package mytomcat_v1; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; /** * * @author zhengrongjun * @version v1.0 */ public class Server_V1 { public static void main(String[] args) { ServerSocket serverSocket = null; Socket client = null; try { serverSocket = new ServerSocket(9999); // 不断接收客户链接 while (true) { // 服务器阻塞等待客户端socket链接过来 client = serverSocket.accept(); // 对客户端里面端请求信息进行处理 InputStream in = client.getInputStream(); // 定义一个读取缓冲池 主要是在inputstram流中读取字节 byte[] buff = new byte[1024]; int len = in.read(buff); if (len > 0) { String msg = new String(buff, 0, len); System.out.println("===="+msg+"======"); OutputStream out = client.getOutputStream(); //构建响应信息 StringBuffer sb = new StringBuffer(); sb.append("HTTP/1.1 200 OK\n"); sb.append("Content-Type: text/html; charset=UTF-8\n"); sb.append("\n"); String html="<html><head><title>卖烧饼咯</title></head></html><body>小曲常常在" +"<font size='14' color='red'>" +new Date() +"</font>" +"<br/>卖烧饼</body></html>"; sb.append(html); out.write(sb.toString().getBytes()); out.flush(); out.close(); } } } catch (Exception e) { } } }
执行效果以下图所示,打开chrome浏览器,在导航栏输入java
http://localhost:9999/docs/index.html
显示以下图所示
web
控制台输出以下图所示chrome
====GET /docs/index.html HTTP/1.1 Host: localhost:9999 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 ======
该版本在版本一的基础上进行优化,使其可以有效的响应静态资源apache
先看第一部分代码优化,以下图所示
红框的部分,咱们能够理解为对请求信息对处理,所以咱们模仿Tomcat构造一个HttpRequst来处理这一段逻辑。编程
另外,咱们须要对静态资源进行响应,所以咱们须要获取输入内容的静态资源地址,即如下部分的内容。
获取以上红框请求地址内容的代码以下浏览器
uri = msg.substring(msg.indexOf("/"),msg.indexOf("HTTP/1.1") - 1);
综上所述,咱们有HttpRequest类以下所示tomcat
package mytomcat_v2; import java.io.IOException; import java.io.InputStream; /** * 对客户端进行处理对业务类 * * @author zhengrongjun * */ public class HttpRequest { private String uri; public String getUri() { return uri; } public HttpRequest(InputStream in) throws IOException { // 对咱们对请求字节流进行解析 resolverRequest(in); } private void resolverRequest(InputStream in) throws IOException { // TODO Auto-generated method stub byte[] buff = new byte[1024]; int len = in.read(buff); if (len > 0) { String msg = new String(buff, 0, len); System.out.println("====" + msg + "======"); // 解析出来 uri uri = msg.substring(msg.indexOf("/"), msg.indexOf("HTTP/1.1") - 1); } else { System.out.println("bad Request!"); } } }
接下来是第二部分的代码优化,以下图所示
以上红框部分主要是对输出信息进行响应,咱们模仿tomcat构造一个HttpResponse对象封装该部分逻辑。
另外,咱们获取用户请求的资源文件路径,根据该路径找到相应静态文件。将该文件写入文件流,输出。
所以,咱们有HttpResponse对象以下所示服务器
package mytomcat_v2; /** * 封装http响应信息 * @author zhengrongjun * */ import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; public class HttpResponse { private OutputStream os = null; public HttpResponse(OutputStream os) { this.os = os; } public void writerFile(String path) throws IOException { FileInputStream fileInputStream = new FileInputStream(path); byte[] buff = new byte[1024]; int len = 0; // 构建响应信息 StringBuffer sb = new StringBuffer(); sb.append("HTTP/1.1 200 OK\n"); sb.append("Content-Type: text/html; charset=UTF-8\n"); sb.append("\n"); os.write(sb.toString().getBytes()); while ((len = fileInputStream.read(buff)) != -1) { os.write(buff, 0, len); } fileInputStream.close(); os.flush(); os.close(); } }
接下来咱们构建测试类,构建以前咱们先去找一些静态资源文件。做者直接去apache的官网下把tomcat给下了下来,而后去以下目录拷贝静态资源文件
apache-tomcat-8.5.28/webapps/docs
将整个docs 文件夹拷贝至你的项目的根目录下
apache-tomcat-8.5.28/webapps/ROOT/favicon.ico
将favicon.ico图片拷贝至你的根目录下
静态资源在你的项目中的结构以下图所示
如今上咱们的Server_V2的代码
package mytomcat_v2; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; /** * * @author zhengrongjun * @version v2.0 */ public class Server_V2 { public static void main(String[] args) { ServerSocket serverSocket = null; Socket client = null; try { serverSocket = new ServerSocket(9999); // 不断接收客户链接 while (true) { // 服务器阻塞等待客户端socket链接过来 client = serverSocket.accept(); // =========请求类处理======= InputStream in = client.getInputStream(); HttpRequest request = new HttpRequest(in); String requestUri = request.getUri(); // =========响应类处理======= OutputStream os = client.getOutputStream(); HttpResponse response = new HttpResponse(os); //请求格式是/html/login.html这种,须要把开头的/删除 response.writerFile(requestUri.substring(1)); client.close(); } } catch (Exception e) { e.printStackTrace(); } } }
测试结果以下:
在浏览器输入
http://localhost:9999/docs/ssl-howto.html
效果以下
你会惊奇的发现样式并不能识别,所以咱们对响应头的部分逻辑进行修改
将
sb.append("HTTP/1.1 200 OK\n"); sb.append("Content-Type: text/html; charset=UTF-8\n"); sb.append("\n");
部分修改成
if(path.endsWith("css")) { sb.append("HTTP/1.1 200 OK\n"); sb.append("Content-Type: text/css; charset=UTF-8\n"); sb.append("\n"); }else { sb.append("HTTP/1.1 200 OK\n"); sb.append("Content-Type: text/html; charset=UTF-8\n"); sb.append("\n"); }
继续启动测试,效果以下
已经可以正常显示
本文给出了两个版本的静态资源的服务器源码,但愿读者可以有所收获。