服务器需要同时处理多个客户端连接,常见并发模型如下。

单线程阻塞模型

一个线程处理一个连接。

流程:

1
2
3
4
accept()
recv()
send()
close()

缺点:

  • 同一时间只能服务一个客户端
  • 并发能力很弱

适合:

  • 学习
  • 简单测试

多进程模型

每个连接创建一个子进程处理。

1
2
主进程 accept()
子进程处理客户端

优点:

  • 进程隔离性好
  • 一个连接崩溃不影响其他连接

缺点:

  • 进程创建销毁开销大
  • 进程间通信复杂

典型场景:

  • 早期 Apache prefork 模型

多线程模型

每个连接创建一个线程处理。

优点:

  • 编程相对简单
  • 比多进程轻量

缺点:

  • 线程数量过多时上下文切换开销大
  • 需要注意线程安全

简单示意:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <thread>

void handleClient(int clientfd) {
char buf[1024];

while (true) {
ssize_t n = recv(clientfd, buf, sizeof(buf), 0);

if (n <= 0) {
break;
}

send(clientfd, buf, n, 0);
}

close(clientfd);
}

// accept 后:
std::thread t(handleClient, clientfd);
t.detach();

线程池模型

提前创建固定数量线程,由线程池处理连接或任务。

优点:

  • 避免频繁创建销毁线程
  • 控制线程数量
  • 更稳定

缺点:

  • 实现复杂度更高
  • 任务调度需要设计

适合:

  • 中等并发服务器
  • 业务处理耗时较长的服务

Reactor 模型

Reactor 是高性能网络服务器常见模型。

核心思想:

使用 IO 多路复用监听事件,事件到来后分发给对应处理器。

常见组合:

1
epoll + 非阻塞 IO + 事件回调

基本结构:

1
2
3
4
5
EventLoop
├── accept 事件
├── read 事件
├── write 事件
└── timer 事件

常见 Reactor 模型:

模型 说明
单 Reactor 单线程 一个线程负责所有 IO 和业务
单 Reactor 多线程 Reactor 负责 IO,线程池处理业务
主从 Reactor 多线程 主 Reactor accept,从 Reactor 处理连接

Proactor 模型

Proactor 是异步 IO 模型。

核心思想:

应用提交异步 IO 请求,操作系统完成后通知应用。

典型平台:

  • Windows IOCP
  • Linux io_uring

与 Reactor 的区别:

模型 特点
Reactor 事件就绪后,应用自己执行 IO
Proactor IO 完成后,系统通知应用