zoukankan      html  css  js  c++  java
  • 理解与模拟一个简单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 }
  • 相关阅读:
    swoole 安装方法 使用即时聊天
    git的介绍以及简单应用
    curl的应用
    linux下监听和同步代码配置
    mac skim 修改背景色
    php 编译安装的一个 configure 配置
    mac mysql error You must reset your password using ALTER USER statement before executing this statement.
    yii2 控制器里 action 大小写组合造成的路由问题
    warning : json_decode(): option JSON_BIGINT_AS_STRING not implemented in xxx
    redis 自启动脚本
  • 原文地址:https://www.cnblogs.com/music180/p/6086430.html
Copyright © 2011-2022 走看看