Tomcat作为开源的轻量级WEB服务器,虽然不是很适合某些大型项目,但是它开源,读其源代码可以很好的提高我们的编程功底和设计思维。Tomcat中用到了很多比较好的设计模式,其中代码风格也很值得我们去效仿。前阵子看了Tomcat源码分析这本书,特此过来分享分享自己的学习过程记录。说得不好,大神不要喷我。
也不废话了,直入主题上代码。Tomcat是什么,Tomcat是一个web服务器,能够接收请求,作出响应。接收请求,作出响应让我们联想到Socket编程。我们可以起一个线程服务ServerSocket来监听本机的8080端口(可配置),然后就可以在浏览器上访问http://localhost:8080/index.html,这个时候就可以通过socket的inputstream获取到浏览器封装的HTTP请求了,然后就可以针对这个请求来大做文章。以下是服务端的代码
      
         1
      
      
        package
      
      
         cn.tim.server.core;
      
      
         2
      
      
         3
      
      
        import
      
      
         java.io.File;
      
      
         4
      
      
        import
      
      
         java.io.IOException;
      
      
         5
      
      
        import
      
      
         java.io.InputStream;
      
      
         6
      
      
        import
      
      
         java.io.OutputStream;
      
      
         7
      
      
        import
      
      
         java.net.InetAddress;
      
      
         8
      
      
        import
      
      
         java.net.ServerSocket;
      
      
         9
      
      
        import
      
      
         java.net.Socket;
      
      
        10
      
      
        11
      
      
        12
      
      
        /**
      
      
        13
      
      
         * HTTP服务器,主类
      
      
        14
      
      
         * 
      
      
        @author
      
      
         TIM
      
      
        15
      
      
         *
      
      
        16
      
      
        */
      
      
        17
      
      
        public
      
      
        class
      
      
         HttpServer {
      
      
        18
      
      
        19
      
      
        20
      
      
        /**
      
      
        21
      
      
             * 端口
      
      
        22
      
      
        */
      
      
        23
      
      
        public
      
      
        int
      
       PORT = 8080
      
        ;
      
      
        24
      
      
        25
      
      
        26
      
      
        /**
      
      
        27
      
      
             * 关闭指令
      
      
        28
      
      
        */
      
      
        29
      
      
        public
      
      
        final
      
      
        static
      
       String SHUTDOWN = "SHUTDOWN"
      
        ;
      
      
        30
      
      
        31
      
      
        32
      
      
        /**
      
      
        33
      
      
             * webroot根目录
      
      
        34
      
      
        */
      
      
        35
      
      
        public
      
      
        static
      
      
        final
      
       String WEB_ROOT = 
      
        36
      
               System.getProperty("user.dir") + File.separator + "WebRoot"
      
        ;
      
      
        37
      
      
        38
      
      
        39
      
      
        public
      
      
        static
      
      
        void
      
      
         main(String[] args) {
      
      
        40
      
      
        41
      
      
        new
      
      
         HttpServer().await();
      
      
        42
      
      
        43
      
      
            }
      
      
        44
      
      
        45
      
      
        46
      
      
        /**
      
      
        47
      
      
             * 线程监听
      
      
        48
      
      
        */
      
      
        49
      
      
        private
      
      
        void
      
      
         await() {
      
      
        50
      
      
        51
      
               ServerSocket server = 
      
        null
      
      
        ;
      
      
        52
      
      
        try
      
      
         {
      
      
        53
      
                   server = 
      
        new
      
       ServerSocket(PORT,1
      
        , 
      
      
        54
      
                           InetAddress.getByName("127.0.0.1"
      
        ));
      
      
        55
      
               } 
      
        catch
      
      
         (Exception e) {
      
      
        56
      
      
                    e.printStackTrace();
      
      
        57
      
      
                }
      
      
        58
      
      
        59
      
      
        boolean
      
       shutdown = 
      
        false
      
      
        ;
      
      
        60
      
      
        while
      
      (!
      
        shutdown) {
      
      
        61
      
                   Socket client = 
      
        null
      
      
        ;
      
      
        62
      
                   InputStream in = 
      
        null
      
      
        ;
      
      
        63
      
                   OutputStream out = 
      
        null
      
      
        ;
      
      
        64
      
      
        try
      
      
         {
      
      
        65
      
      
        //
      
      
         获取到请求socket
      
      
        66
      
                       client =
      
         server.accept();
      
      
        67
      
                       in =
      
         client.getInputStream();
      
      
        68
      
                       out =
      
         client.getOutputStream();
      
      
        69
      
      
        70
      
      
        //
      
      
         生成request同时解析请求
      
      
        71
      
                       Request request = 
      
        new
      
      
         Request(in);
      
      
        72
      
      
                        request.parse();
      
      
        73
      
      
        74
      
      
        //
      
      
         生成response
      
      
        75
      
                       Response response = 
      
        new
      
      
         Response(out);
      
      
        76
      
      
                        response.setRequest(request);
      
      
        77
      
      
        //
      
      
         根据资源定位符发送对应资源
      
      
        78
      
      
                        response.sendStaticResource();
      
      
        79
      
      
                        client.close();
      
      
        80
      
      
        81
      
                       shutdown =
      
         request.getUri().equals(SHUTDOWN);
      
      
        82
      
                   } 
      
        catch
      
      
         (IOException e) {
      
      
        83
      
      
        //
      
      
         TODO Auto-generated catch block
      
      
        84
      
      
                        e.printStackTrace();
      
      
        85
      
      
        continue
      
      
        ;
      
      
        86
      
      
                    }
      
      
        87
      
      
        88
      
      
                }
      
      
        89
      
      
        90
      
      
            }
      
      
        91
      
      
        92
      
       }
    
  既然服务端HttpServer都出来了,Request都干些什么,request顾名思义,请求肯定是封装请求的一个JAVA类,肯定要能够解析HTTP请求,例如访问静态资源,就得获取到静态资源的资源定位符uri。
HTTP请求Request类:
      
        1
      
       GET /index.html HTTP/1.1
      
        2
      
       Accept: text/html, application/xhtml+xml, *
      
        /*
      
      
        3
      
      
        Accept-Language: zh-CN
      
      
        4
      
      
        User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; MALCJS)
      
      
        5
      
      
        Accept-Encoding: gzip, deflate
      
      
        6
      
      
        Host: localhost:8080
      
      
        7
      
      
        DNT: 1
      
      
        8
      
      
        Connection: Keep-Alive
      
      
        9
      
      
        Cookie: principal=user:admin__password:admin
      
    
  
      
         1
      
      
        package
      
      
         cn.tim.server.core;
      
      
         2
      
      
         3
      
      
        import
      
      
         java.io.IOException;
      
      
         4
      
      
        import
      
      
         java.io.InputStream;
      
      
         5
      
      
         6
      
      
        /**
      
      
         7
      
      
         * 封装请求
      
      
         8
      
      
         * 
      
      
        @author
      
      
         TIM
      
      
         9
      
      
         *
      
      
        10
      
      
        */
      
      
        11
      
      
        public
      
      
        class
      
      
         Request {
      
      
        12
      
      
        13
      
      
        14
      
      
        /**
      
      
        15
      
      
             * 请求输入流
      
      
        16
      
      
        */
      
      
        17
      
      
        private
      
      
         InputStream in;
      
      
        18
      
      
        19
      
      
        20
      
      
        /**
      
      
        21
      
      
             * 资源定位符
      
      
        22
      
      
        */
      
      
        23
      
      
        private
      
      
         String uri;
      
      
        24
      
      
        25
      
      
        26
      
      
        /**
      
      
        27
      
      
             * 初始化request,传入socket输入流
      
      
        28
      
      
             * 
      
      
        @param
      
      
         in
      
      
        29
      
      
        */
      
      
        30
      
      
        public
      
      
         Request(InputStream in) {
      
      
        31
      
      
        this
      
      .in =
      
         in;
      
      
        32
      
      
            }
      
      
        33
      
      
        34
      
      
        35
      
      
        /**
      
      
        36
      
      
             * 根据请求字符串解析请求
      
      
        37
      
      
        */
      
      
        38
      
      
        public
      
      
        void
      
      
         parse() {
      
      
        39
      
      
        40
      
      
        try
      
      
         {
      
      
        41
      
      
        byte
      
      [] bytes = 
      
        new
      
      
        byte
      
      [2048
      
        ];
      
      
        42
      
      
        int
      
       i =
      
         in.read(bytes);
      
      
        43
      
      
        44
      
                   StringBuffer buffer = 
      
        new
      
       StringBuffer(2048
      
        );
      
      
        45
      
      
        for
      
      (
      
        int
      
       j=0; j<i; j++
      
        ) {
      
      
        46
      
                       buffer.append((
      
        char
      
      
        )bytes[j]);
      
      
        47
      
      
                    }
      
      
        48
      
      
                    System.out.println(buffer.toString());
      
      
        49
      
                   uri =
      
         parseUri(buffer.toString());
      
      
        50
      
      
                    System.out.println(uri);
      
      
        51
      
               } 
      
        catch
      
      
         (IOException e) {
      
      
        52
      
      
        //
      
      
         TODO Auto-generated catch block
      
      
        53
      
      
                    e.printStackTrace();
      
      
        54
      
      
                }
      
      
        55
      
      
        56
      
      
            }
      
      
        57
      
      
        58
      
      
        59
      
      
        /**
      
      
        60
      
      
             * 解析出资源定位符uri,实际上就是用字符串分拆获取到GET /index.html HTTP/1.1中的/index,html
      
      
        61
      
      
             * 
      
      
        @return
      
      
        62
      
      
        */
      
      
        63
      
      
        private
      
      
         String parseUri(String requestString) {
      
      
        64
      
      
        65
      
      
        int
      
       index1 = requestString.indexOf(" "
      
        );
      
      
        66
      
      
        if
      
      (index1 != -1
      
        ) {
      
      
        67
      
      
        int
      
       index2 = requestString.indexOf(" ", index1+1
      
        );
      
      
        68
      
      
        if
      
      (index2>
      
        index1) {
      
      
        69
      
      
        return
      
       requestString.substring(index1+1
      
        , index2);
      
      
        70
      
      
                    }
      
      
        71
      
      
                }
      
      
        72
      
      
        return
      
      
        null
      
      
        ;
      
      
        73
      
      
            }
      
      
        74
      
      
        75
      
      
        76
      
      
        public
      
      
         InputStream getIn() {
      
      
        77
      
      
        return
      
      
         in;
      
      
        78
      
      
            }
      
      
        79
      
      
        80
      
      
        81
      
      
        public
      
      
         String getUri() {
      
      
        82
      
      
        return
      
      
         uri;
      
      
        83
      
      
            }
      
      
        84
      
      
        85
      
       }
    
  获取到资源定位符,接下来就是根据资源定位符来作出相应,当然实际的Tomcat处理方式肯定是很复杂的,我们只模仿其中简单的方式,访问静态资源。
Response类:
      
         1
      
      
        package
      
      
         cn.tim.server.core;
      
      
         2
      
      
         3
      
      
        import
      
      
         java.io.File;
      
      
         4
      
      
        import
      
      
         java.io.FileInputStream;
      
      
         5
      
      
        import
      
      
         java.io.IOException;
      
      
         6
      
      
        import
      
      
         java.io.InputStream;
      
      
         7
      
      
        import
      
      
         java.io.OutputStream;
      
      
         8
      
      
         9
      
      
        public
      
      
        class
      
      
         Response {
      
      
        10
      
      
        11
      
      
        12
      
      
        /**
      
      
        13
      
      
             * 输出
      
      
        14
      
      
        */
      
      
        15
      
      
        private
      
      
         OutputStream out;
      
      
        16
      
      
        17
      
      
        18
      
      
        /**
      
      
        19
      
      
             * 缓冲大小
      
      
        20
      
      
        */
      
      
        21
      
      
        public
      
      
        final
      
      
        static
      
      
        int
      
       BUFFER_SIZE = 2048
      
        ;
      
      
        22
      
      
        23
      
      
        24
      
      
        /**
      
      
        25
      
      
             * 请求,根据请求作出对应的响应
      
      
        26
      
      
        */
      
      
        27
      
      
        private
      
      
            Request request;
      
      
        28
      
      
        29
      
      
        30
      
      
        public
      
      
         Response(OutputStream out) {
      
      
        31
      
      
        this
      
      .out =
      
         out;
      
      
        32
      
      
            }
      
      
        33
      
      
        34
      
      
        35
      
      
        /**
      
      
        36
      
      
             * 发送静态资源
      
      
        37
      
      
        */
      
      
        38
      
      
        public
      
      
        void
      
      
         sendStaticResource() {
      
      
        39
      
      
        40
      
      
        byte
      
      [] bytes = 
      
        new
      
      
        byte
      
      
        [BUFFER_SIZE];
      
      
        41
      
               InputStream in = 
      
        null
      
      
        ;
      
      
        42
      
      
        try
      
      
         {
      
      
        43
      
                   File file = 
      
        new
      
      
         File(HttpServer.WEB_ROOT, request.getUri());
      
      
        44
      
      
        //
      
      
         请求的资源存在
      
      
        45
      
      
        if
      
      
        (file.exists()) {
      
      
        46
      
                       in = 
      
        new
      
      
         FileInputStream(file);
      
      
        47
      
      
        int
      
      
         ch;
      
      
        48
      
      
        if
      
      ((ch=in.read(bytes, 0, BUFFER_SIZE))!=-1
      
        ) {
      
      
        49
      
                           out.write(bytes, 0
      
        , ch);
      
      
        50
      
      
                        }
      
      
        51
      
      
                    } 
      
      
        52
      
      
        //
      
      
         请求资源不存在报404
      
      
        53
      
      
        else
      
      
         {
      
      
        54
      
                       String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
      
        55
      
                         "Content-Type: text/html\r\n" +
      
        56
      
                         "Content-Length: 23\r\n" +
      
        57
      
                         "\r\n" +
      
        58
      
                         "<h1>File Not Found</h1>"
      
        ;
      
      
        59
      
      
                        out.write(errorMessage.getBytes());
      
      
        60
      
      
                    }
      
      
        61
      
               } 
      
        catch
      
      
         (Exception e) {
      
      
        62
      
      
        //
      
      
         TODO Auto-generated catch block
      
      
        63
      
      
                    e.printStackTrace();
      
      
        64
      
               } 
      
        finally
      
      
         {
      
      
        65
      
      
        if
      
      (in!=
      
        null
      
      
        )
      
      
        66
      
      
        try
      
      
         {
      
      
        67
      
      
                            in.close();
      
      
        68
      
                       } 
      
        catch
      
      
         (IOException e) {
      
      
        69
      
      
        //
      
      
         TODO Auto-generated catch block
      
      
        70
      
      
                            e.printStackTrace();
      
      
        71
      
      
                        }
      
      
        72
      
      
                }
      
      
        73
      
      
        74
      
      
            }
      
      
        75
      
      
        76
      
      
        77
      
      
        public
      
      
        void
      
      
         setRequest(Request request) {
      
      
        78
      
      
        this
      
      .request =
      
         request;
      
      
        79
      
      
            }
      
      
        80
      
      
        81
      
       }
    
  这样,一个简单的Web服务器就实现了,可以访问静态资源,直接在浏览器上访问,没有找到对应的资源还可以报404错误。今天就写到这里,继续努力。。。


 
					 
					