• 理解与模拟一个简单web服务器


      先简单说下几个概念,根据自己的理解,不正确请见谅。

    web服务器

         首先要知道什么是web服务器,简单说web服务器就是可以使用HTTP传输协议与客户端进行通信的服务器。最初的web服务器只能用来处理静态页面,而tomcat服务器更加强大,不仅可以处理静态页面,还可以运行java类文件,动态创建页面并返回给浏览器,之所以说tomcat是个容器,就是可以运行servle类的容器,同时可以处理http请求,并返回相应内容。

    HTTP协议

        http协议是应用层协议,底层使用tcp建立可靠传输连接。所谓协议就是规定了传输内容的规范或格式。先看一个浏览器的http请求:   

      

    
    
    1 POST /inner/index.html HTTP/1.1
    2 Host: localhost:8080
    3 Connection: keep-alive
    4 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    5 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0
    6 Accept-Encoding: gzip,deflate,sdch
    7 Accept-Language: zh-CN,zh;q=0.8
    8 
    9 name=ligen&age=21

      

        http请求包括三部分:

      1-7行可以归为请求头部分,然后8是空行用以区分实体部分,9行是请求实体内容

    1. (代码1)请求方法--uri--协议/版本
    2. (代码2-7)请求头
    3. (代码9)实体

      第一行POST /inner/index.html HTTP/1.1,POST就是请求方法(还有get等请参考其它),然后是空格;/inner/index.html是请求的资源,一般是相对于根路径的,所以总是以“/”开头;最后是协议和版本。

      http的响应格式与请求类似:

      

    1 HTTP/1.1 200 OK
    2 server:tomcat
    3 Content-Type:text/html
    4 Content-Length:100
    5 
    6 <html>
    7 ......
    8 </html>

      第一行指定了协议和版本,接着是状态码200,服务器一切运行正常,与请求类似,响应实体部分与信息头部分通过一个空行分隔。

    开始建立web服务器

      现在开始着手建立一个简单的web服务器,需要大家有socket基础(了解即可),服务器的基本功能就是基于客户端的请求,建立请求对象request,然后处理相应逻辑找到资源,并封装成response对象通过http将数据传回客户端。因为需要建立三个类:

    • HttpServer 使用socket负责建立服务器,等待客户端连接,建立连接后,根据请求信息初始化Request、Response
    • Request 获取socket的InputStream,封装了客户端的请求信息
    • Response 对应Request的返回信息,获取socket的OutputStream处理返回数据 

    (一)HttpServer类

      HttpServer主要建立本地8080端口服务器,等待连接请求,建立请求后使用socket的InputStream和OutputStream分别初始化Request和Response对象。

     1 public class HttpServer {
     2     pupublic void await() {
     3         ServerSocket serverSocket = null;
     4         int port = 8080;
     5         try {
     6             serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
     7         } catch (IOException e) {
     8             e.printStackTrace();
     9             System.exit(1);
    10         }
    11         while (true){
    12             Socket socket = null;
    13             InputStream inputStream = null;
    14             OutputStream outputStream = null;
    15             try {
    16                 socket = serverSocket.accept();
    17                 inputStream = socket.getInputStream();
    18                 outputStream = socket.getOutputStream();
    19                 Request request = new Request(inputStream);//使用连接的inputStream初始化Request
    20                 request.Parse();//Parse用于解析原始HTTP请求数据
    21                 Response response = new Response(outputStream);
    22                 response.setRequest(request);
    23                 response.sendStaticResource();
    24                 socket.close();
    25             } catch (IOException e) {
    26                 e.printStackTrace();
    27             }
    28         }
    29     }
    30 }    

     (二)Request类

     1 public class Request{
     2     
     3     private String uri;
     4     private InputStream in;
     5     
     6     public Request(InputStream in){
     7         this.in = in;
     8     }
     9     //根据请求头信息获取uri,如GET /index.html HTTP/1.1 ,可以返回/index.html
    10     public String parseUri(String request){
    11         int index1,index2;
    12         index1 = request.indexOf(" ");
    13         if (index1 != -1){
    14             index2 = request.indexOf(" ", index1+ 1);
    15             if (index1 < index2)
    16                 return request.substring(index1 + 1, index2);
    17         }
    18         return null;
    19     }
    20     //根据socket的InputStream读取整个字节流,存储在字节数组中,然后使用内存中的字节数组构建StringBUffer对象
    21     public void Parse(){
    22         StringBuffer request = new StringBuffer(2048);
    23         byte[] bs = new byte[2048];
    24         int i;
    25         try {
    26             i = in.read(bs);
    27         } catch (IOException e) {
    28             e.printStackTrace();
    29             i = -1;
    30         }
    31         
    32         for(int j=0; j<i; j++){
    33             request.append((char)bs[j]);
    34         }
    35         System.out.println(request.toString());
    36         uri = parseUri(request.toString());
    37     }
    38     
    39     public String getUri() {
    40         return uri;
    41     }
    42 }

     (三)Response类

      Response使用socket返回的OutputStream构建对象,setRequest()方法使用初始化后的Request对象出给Response,sendStaticResource()用于发送静态资源,如html文件。

     1 public class Response implements ServletResponse{
     2     
     3     private static final int BUFFER_SIZE = 1024;
     4     private Request request;
     5     private OutputStream out;
     6     private PrintWriter writer;
     7     
     8     public  Response(OutputStream out) {
     9         this.out = out;
    10     }
    11     
    12     public  void setRequest(Request request) {
    13         this.request = request;
    14     }
    15     
    16     public void sendStaticResource() throws IOException{
    17         byte[] buffer = new byte[BUFFER_SIZE];
    18         FileInputStream fis = null;
    19         File file = new File(Constant.WEB_ROOT, request.getUri());
    20         try {
    21             fis = new FileInputStream(file);
    22             int ch = fis.read(buffer, 0, BUFFER_SIZE);
    23             while (ch != -1){
    24                 out.write(buffer, 0, BUFFER_SIZE);
    25                 ch = fis.read(buffer, 0, BUFFER_SIZE);
    26             }
    27         } catch (FileNotFoundException e) {//当文件不存在时,返回错误信息
    28             String html = "<h1>file not found</h1>";
    29             String errorMsg = "HTTP/1.1 404 file not found
    " + 
    30                     "Content-Type: text/html
    " + 
    31                     "Content-Length: " + html.getBytes().length + "
    " +
    32                     "
    " +
    33                     html;
    34             out.write(errorMsg.getBytes());
    35         }
    36         finally {
    37             if(fis != null){
    38                 fis.close();
    39             }
    40         }
    41     }
    42 }

      (四)创建MyServer类,启动服务器

    1 public class MyServer {
    2     public static void main(String[] args) {
    3         HttpServer server = new HttpServer();
    4         server.await();
    5     }
    6 }
  • 相关阅读:
    Java线程池
    Servlet实现网页十天免登陆功能
    代码实现QQ消息轰炸
    数组模拟栈数据结构
    约瑟夫问题以及环形链表的解决方案
    ServletConfig中的方法
    Servlet的生命周期
    数组模拟环形队列
    数组模拟队列
    多线程实现奇偶数的依次输出
  • 原文地址:https://www.cnblogs.com/music180/p/6086430.html
Copyright © 2020-2023  润新知