• Tomcat源码学习记录--web服务器初步认识


      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
    " +
    55                   "Content-Type: text/html
    " +
    56                   "Content-Length: 23
    " +
    57                   "
    " +
    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错误。今天就写到这里,继续努力。。。

      

  • 相关阅读:
    考试题1
    九九乘法表
    面向对象
    *****用循环运用
    编辑实现逻辑运算和循环计数
    求:1-3+5-7+...-99+101的值的(分析求解)。
    三层for循环求解组成三角形边的组合
    for循环的应用
    Java基础输出语句
    习题4 编写一个方法method(),判断一个数能否同时被3和5整除
  • 原文地址:https://www.cnblogs.com/TimBing/p/3627872.html
Copyright © 2020-2023  润新知