78

自己动手实现静态资源服务器

 5 years ago
source link: http://www.10tiao.com/html/457/201806/2651089582/2.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

作者:孤独烟
原文:https://www.cnblogs.com/rjzheng/p/8750265.html

引言

本文利用java自带的socket编程实现了一个简单的静态资源服务器,可以响应静态资源。本文一共有两个版本的源码。第一个版本名为Server_v1,该版本实现了一个简单的socket的服务器,帮助读者回忆socket编程。第二个版本名为Server_v2,该版本是对第一版的改良,给出了改良思路,做出了必要的封装,让其能够响应css、html、jpg等静态资源。

正文

版本一

该版本实现一个简单的socket服务器,针对浏览器的请求,能够返回相应的页面。
其源码如下:

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浏览器,在导航栏输入

http://localhost:9999/docs/index.html
显示如下图所示

控制台输出如下图所示

====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
======

版本二

该版本在版本一的基础上进行优化,使其能够有效的响应静态资源

(1)步骤一

先看第一部分代码优化,如下图所示

红框的部分,我们可以理解为对请求信息对处理,因此我们模仿Tomcat构造一个HttpRequst来处理这一段逻辑。

另外,我们需要对静态资源进行响应,因此我们需要获取输入内容的静态资源地址,即以下部分的内容。

获取以上红框请求地址内容的代码如下

uri = msg.substring(msg.indexOf("/"),msg.indexOf("HTTP/1.1") - 1);
综上所述,我们有HttpRequest类如下所示

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!");
       }
   }
}
(2)步骤二

接下来是第二部分的代码优化,如下图所示

以上红框部分主要是对输出信息进行响应,我们模仿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();
   }
}
(3)步骤三

接下来我们构建测试类,构建之前我们先去找一些静态资源文件。作者直接去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");
       }

继续启动测试,效果如下

已经能够正常显示

总结

本文给出了两个版本的静态资源的服务器源码,希望读者能够有所收获。



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK