在 Java Web 技术体系中,无论我们使用的是 Servlet、Spring MVC、Spring Boot 还是 Netty,它们最终都绕不开一个事实:

所有 Web 请求,本质上都是通过 Socket 传输的字节流。
Servlet 容器(Tomcat/Jetty)负责把字节流转换成 HTTP 对象,再交给应用处理。

这篇文章将从“浏览器发送一个 HTTP 请求”开始,一层层剖开 Servlet 的幕布,包括:

  • Socket 背后的 TCP 通信细节

  • Tomcat 如何管理线程、处理 Socket

  • Servlet 的生命周期与多线程模型

  • HTTP 协议解析与响应构建

  • NIO、Selector 模型与现代服务器优化

这是一次横跨网络编程 + 协议 + Web 容器架构的完整讲解。


一、Socket:一切网络通信的起点

1. TCP 是如何保证“可靠”的?

当两个进程想通信时,它们不能直接读写内存,只能通过网络发送数据。TCP 提供:

  • 三次握手:保证连接建立

  • 序列号 / ACK:保证数据按顺序

  • 重传机制:保证数据不会丢

  • 滑动窗口:保证流量控制

  • 拥塞控制:保证网络不会被压垮

你编写的 Socket 程序实际上使用的是 TCP 内核模块:

Socket socket = new Socket("127.0.0.1", 8080);

这里的 Socket 不是 TCP,是 Java 对 TCP 的封装。


2. ServerSocket 是如何接收连接的?

代码:

ServerSocket server = new ServerSocket(8080);
Socket s = server.accept();

底层过程是:

  1. 服务端监听 8080 端口,进入 LISTEN 状态

  2. 客户端向这个端口发起 SYN

  3. 内核完成 TCP 三次握手

  4. 内核把这个已建立连接加入 accept 队列

  5. accept() 从队列取出一个连接,返回 Socket 对象

  6. 后续所有 read/write 都是对这个连接的操作

所以:

每一个客户端都会对应一个独立的 Socket 连接。


二、一个 HTTP 请求到底长什么样?

浏览器访问:

GET /hello HTTP/1.1
Host: localhost:8080
User-Agent: Chrome/...
Accept: text/html
Connection: keep-alive

这其实就是纯文本,通过 Socket 发送到服务器。

服务器看到的只是字节:

47 45 54 20 2F 68 65 6C 6C 6F ...
G  E  T     /  h  e  l  l  o

Web 容器需要:

  1. 把字节流转成字符串

  2. 再解析出:URL、Header、Method、Body

  3. 创建 HttpServletRequest 包装它

  4. 把响应对象 HttpServletResponse 包装输出流

Servlet 层看到的是高级对象,但背后全是 Socket。


三、Tomcat 内部如何处理 Socket?(核心知识)

要深入理解 Servlet,就必须拆开 Tomcat 的线程模型。

1. Tomcat 的整体架构

┌──────────────────────────────────┐
│           Tomcat Server          │
├──────────────────────────────────┤
│ Connector (负责 Socket + HTTP)   │
├──────────────────────────────────┤
│ Container (负责 Servlet 分发)    │
└──────────────────────────────────┘

Connector 负责:

  • 监听 8080

  • 接收 Socket 连接

  • 解析 HTTP 请求

  • 封装 request/response

  • 交给 Container

Container 负责:

  • Servlet 映射

  • 调用 servlet.service()

  • 返回响应


2. Tomcat 默认使用的线程模型(BIO → NIO → APR)

① 早期 BIO(Blocking IO)模型

每个 Socket 对应一个线程:

Client A  ──> Thread A
Client B  ──> Thread B

问题:用户多时线程数量爆炸。

② Modern Tomcat 使用 NIO + Selector(推荐)

NIO 让一个线程管理大量连接:

Selector Thread
   ├─ Socket A 可读
   ├─ Socket B 可写
   ├─ Socket C 可读
   └─ ...

优点:大量并发下不会创建巨量线程。

③ 高性能 APR(Native Tomcat)

基于 Apache Portable Runtime,接近 C 语言服务器性能。


四、Servlet 的生命周期与线程模型(重点)

Servlet 不由你创建,而由容器管理:

init() → service()(多次) → destroy()
  • init():只执行一次,用来加载资源(连接池、缓存等)

  • service():浏览器每次请求都会触发(并发执行)

  • destroy():服务器关闭时执行

多线程是关键!

一个 Servlet 实例会被多个线程并发访问。

例如:

private int count = 0;

protected void doGet(...) {
    count++;   // 线程安全风险 !!!
}

这是经典错误。

正确方式:

  • 使用局部变量

  • 使用线程安全类(AtomicInteger)

  • 或同步代码块


五、Tomcat 是如何把一次请求交给 Servlet 的?(完整流程)

以下是一次请求完整链路的详细过程——你在其他博客看不到这么细的版本。

浏览器
  ↓ 发送 HTTP
Tomcat Connector
  ↓ accept() 拿到 Socket
  ↓ 解析 HTTP
生成 Request 与 Response 对象
  ↓
交给 Container
  ↓
找到与 URL 对应的 Servlet
  ↓
创建线程 (从线程池取)
  ↓
调用 servlet.service()
  ↓
调用 doGet()/doPost()
  ↓
Servlet 写入响应缓冲区
  ↓
Tomcat 通过 Socket 返回给客户端

所有 Servlet 框架(Spring MVC / Spring Boot)最终都是这个流程。


六、Socket + Servlet 综合理解图

                (TCP Socket)
Browser  <------------------------>  Tomcat Connector
                                         │
            HTTP 字节流解析               │
                                         ▼
                             HttpServletRequest / Response
                                         │
                                         ▼
                                   Servlet Container
                                         │
                               调度并调用目标 Servlet
                                         │
                                         ▼
                                业务处理 + 写输出流
                                         │
                                         ▼
                     Tomcat 再用 Socket 把 HTTP 返回给浏览器

七、如何用 Socket 手写一个迷你版 Servlet 容器?(深度理解)

要真正理解 Servlet,你可以自己写一个 迷你版 Tomcat

  1. 使用 ServerSocket 监听 8080

  2. 读取 HTTP 请求头

  3. 解析 URL

  4. 找到对应的“Servlet 类”(你自己写的)

  5. 调用其 service() 方法

  6. 返回标准 HTTP 响应

这种“模拟 Tomcat”的练习能帮助你完全理解 Servlet 的工作机制。

如果你需要,我可以为你生成完整源码 + zip 下载。


八、进阶阅读:Servlet 与现代 Web 技术的关系

1. Spring MVC / Spring Boot

Servlet 是底层基础。
Spring Boot 默认使用 Tomcat 作为内置服务器。

2. Netty 与 Reactor 模型

更高性能,更适合分布式系统、网关、微服务底层通信。

3. Nginx + Tomcat 架构

Nginx 负责反向代理、压缩、负载均衡,Tomcat 负责业务逻辑。


更多推荐