全国协议5人面授小班,企业级独立开发考核,转业者的IT软件工程师基地 登录/注册 | 如何报名
当前位置: 服务端相关   >  手写 WEB 服务器和 HTTP 协议
admin · 更新于 2021-08-06

1. Http服务基本要素

1.1 监听连接

浏览器每发起一次请求都需要跟服务端建立连接,服务端要时刻监听有没有客户端连接。传输层协议有 TCP/UDP 两种,实现起来并没有强制说用哪一种,下面是官方文档对 Http 连接的说明:

HTTP communication usually takes place over TCP/IP connections. The default port is TCP 80 .

文档中指明了连接通常用的是 TCP, TCP 不用考虑数据包乱序,丢失这些问题,实现起来更简单,高效。在代码层我们可以用 Socket 来实现我们的 TCP 传输服务。

1.2 接收数据

Socket 监听连接,在没有连接到来之前一直是阻塞在 serverSocket.accept(); 有请求过来就可以运行到下面的代码,然后可以根据我们的输入流读取信息,根据 Http 协议拆开获取我们要的请求数据。

1.3 返回数据

根据业务处理完获得返回实体数据,然后遵从 Http 协议格式构造返回的消息报文。浏览器获得到的数据也会根据 Http 协议进行渲染。

2. Http报文格式

Http 协议请求报文的本质就是一堆字符串,只是这堆字符是有格式的,发送方跟接收方都需要按照这个格式来拼接和拆解内容。我们要实现一个 Web 服务,了解这个是最基本的要素。

以下截图的报文是通过 tcpflow(一款功能强大的、基于命令行的免费开源工具)在 Linux 系统抓包获取的。

sudo tcpflow -c port 8080
代码块
  • 1

2.1 Request

图中各种请求首部字段的具体含义/用途,会在下面章节中详细讲解到。

2.2 Response

一般情况下,服务器收到客户端的请求后,就会有一个 Http 的响应消息,Http 响应也由 4 部分组成,分别是:状态行、响应头、空行 和 响应实体。

图中的首部字段和返回内容(响应实体)中间是有一个空行的。

3. 实现

3.1 效果

  • Web 服务端监听 8090 端口;
  • 本地浏览器访问 8090 页面显示 hello tomcat

3.2 代码

package com.hanma.mytomcat.tomcat;import Java.io.IOException;import Java.io.OutputStream;import Java.net.ServerSocket;import Java.net.Socket;/**
 * Mytomcat
 *
 * @author zhourj
 * description
 */public class Mytomcat {
    public static void main(String[] args) {
        Mytomcat server = new Mytomcat();
        server.start();
    }
    private void start(){
        try {
            //开启一个 Socket 服务端,并监听 8090 端口
            ServerSocket serverSocket = new ServerSocket(8090);
            do {
                //阻塞,直到有客户端连接上,才会执行后面的逻辑
                Socket socket = serverSocket.accept();
                //处理数据
                hander(socket);
            } while (true);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * http response
     *  第一行 协议 返回状态
     *  第二行 媒体类型 josn/html
     *  第三行 空
     *  内容
     * @param socket
     */
    private void hander(Socket socket) throws IOException {
        //拼接返回的 request 报文
        StringBuilder responseBuilder = new StringBuilder();
        responseBuilder		        //返回 200 状态码,表示请求成功
		        .append("HTTP/1.1 200 \r\n")
		        //告诉请求的客户端,返回的内容是 text/html 格式的
                .append("Content-Type: text/html\r\n")
                //首部字段和消息实体中间的空行
                .append("\r\n")
                //内容部分
                .append("hello tomcat");
		//获取客户端通道的输出流
        OutputStream outputStream = socket.getOutputStream();
        //往输出流通道写消息
        outputStream.write(responseBuilder.toString().getBytes());
        //流是有缓存机制的,写消息的时候不一定立马发出去,刷一下才能保证数据发送出去
        outputStream.flush();
        //关闭输出流通道
        outputStream.close();
    }}
代码块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

上面的代码初学者可以自己模仿着写一个,相信对 Http 会有很深刻的体验。代码中主要是监听连接,客户端连接后,根据 Http 协议进行字符串的拼接返回给客户端,客户端浏览器接收到是标准的 Http 格式就会进行渲染。

4. 小结

这边的代码虽然很简单,但是最核心的 Http 服务雏形已经展示出来了,成熟的 Http 服务可以在这基础上对以下模块进行优化:

  • 针对请求事件的 线程 / IO 优化;
  • Servlet 协议支持;
  • 配置独立管理;
  • Http协议内容完善(比如缓存机制);
  • 支持虚拟主机配置;
  • 支持代理;
  • rewrite 机制;
  • 安全认证。


为什么选择汉码未来