简介:
Reactor 反应堆模式是一种 事件驱动 的编程模型,核心是让框架(反应堆)统一管理事件,应用只需专注业务逻辑。常见于高性能网络编程(如 Redis、Nginx),用 “事件监听 + 回调处理” 解耦 I/O 操作,支持高并发。
工作流程(餐厅版)
-
初始化:
Reactor 启动,用epoll
监控事件源(门口、餐桌)。
→ 类似经理上班,打开 “监控系统” 看有没有新客 / 服务需求。 -
事件监听:
Reactor 调用epoll_wait
阻塞等待事件。
→ 经理坐着等,直到有人喊 “新客” 或 “加菜”。 -
事件分发:
事件发生(如门口有新客),Reactor 找到对应的 Handler(服务员)。
→ 经理喊:“小王,门口接新客!” -
业务处理:
Handler 处理事件(接客、写数据、读请求)。
→ 服务员带新客入座、记录需求。 -
循环:
处理完事件,Reactor 继续监听下一轮事件。
→ 经理回去继续等,循环往复。
// Reactor 核心逻辑:监听事件 → 分发 → 处理
void Reactor::run() {
while (!stop) {
// 1. 等事件(epoll_wait)
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
if (n < 0) break;
// 2. 遍历事件,分发处理
for (int i = 0; i < n; i++) {
int fd = events[i].data.fd;
if (fd == listensock) {
// 事件源:新连接 → 调用 accept 处理器
acceptHandler();
} else {
// 事件源:普通 socket → 调用 读写处理器
ioHandler(fd);
}
}
}
}
// 处理新连接(Handler)
void Reactor::acceptHandler() {
int clientfd = accept(listensock, ...);
// 设为非阻塞 + ET 模式(配合 Reactor)
setNonBlock(clientfd);
epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, EPOLLIN | EPOLLET);
// 关联业务处理器(如 HttpHandler)
handlers[clientfd] = new HttpHandler(clientfd);
}
// 处理读写事件(Handler)
void Reactor::ioHandler(int fd) {
auto handler = handlers[fd];
// 读数据(非阻塞 + ET 需循环读)
while (true) {
int n = read(fd, buf, sizeof(buf));
if (n < 0) {
if (errno == EAGAIN) break; // 读完,退出循环
// 处理错误,关闭连接
close(fd);
handlers.erase(fd);
break;
} else if (n == 0) {
// 客户端关闭
close(fd);
handlers.erase(fd);
break;
}
// 业务逻辑:解析请求、处理、响应
handler->process(buf, n);
}
}
关键特点(为什么高效?)
- 解耦 I/O 与业务:
Reactor 负责 “等事件”,Handler 负责 “做业务”,代码不用混在一起。 - 支持高并发:
一个 Reactor 可监控成千上万个事件源(如 socket),用epoll
避免阻塞。 - 事件驱动:
只有事件发生时才处理,不用轮询,资源利用率高。
5. 优缺点(什么时候用?)
优点:
- 高并发友好:用
epoll
监控大量连接,单线程也能扛高并发。 - 逻辑清晰:I/O 事件和业务处理分离,代码易维护。
- 可扩展:新增业务(如 Redis 的 String/Hash 操作),只需加 Handler。
缺点:
- 单线程瓶颈:若 Handler 处理耗时操作(如磁盘 IO),会阻塞整个 Reactor。
→ 解决:用 多 Reactor 模式(主 Reactor 负责接连接,子 Reactor 负责读写)。 - ET 模式易错:需严格循环读写,否则丢数据(如忘记
EAGAIN
判断)。
6. 对比:Reactor vs 传统阻塞 I/O
模型 | 传统阻塞 I/O | Reactor 模式 |
---|---|---|
线程数 | 一个连接一个线程(高并发时爆炸) | 单线程 / 少量线程(靠事件驱动) |
阻塞问题 | 线程阻塞在 read/write | 只有 Reactor 阻塞在 epoll_wait |
适用场景 | 连接少、逻辑简单 | 高并发网络服务(如 Nginx、Redis) |
总结:Reactor 是做什么的?
Reactor 反应堆模式,本质是让框架帮你 “等事件、分任务”,你只需要写 “事件发生后做什么”。
- 像餐厅经理:盯着所有事件(新客、加菜),有事就喊对应服务员处理。
- 核心价值:用事件驱动替代轮询,把 “人等事” 变成 “事找人”,大幅提升高并发场景下的效率。
理解 Reactor 后,再看 Nginx、Redis 的网络模型,就会发现它们都是这套逻辑的延伸ovo
基于 Reactor 模式的 TCP 服务器框架设计
用 C++ 智能指针和 Channel/Connection 等组件,实现事件驱动的高并发网络编程,核心是 “解耦业务与网络 I/O”
1. 核心组件与分层
层级 / 组件 | 作用 |
---|---|
OS(最底层) | 提供 epoll 等系统调用,负责监控 fd 事件(如数据可读、新连接)。 |
epoll 层 | 封装 epoll 操作,管理 fd 和事件,向上层(Connection )通知事件。 |
Connection 层 | 每个 Connection 对应一个客户端连接,关联 Channel ,管理读写缓冲区、状态。 |
Channel 层 | 封装 fd 和事件(如 EPOLLIN /EPOLLOUT ),是 Reactor 模式的 “事件载体”。 |
Listener | 监听新连接的特殊 Connection ,收到新连接时创建普通 Connection 。 |
业务 / Protocol 层 | 处理具体逻辑(如解析协议、业务计算),与网络 I/O 解耦。 |
2. 关键设计逻辑
(1)“Reactor 模式落地”
- 事件驱动:
epoll
监控fd
事件 → 触发Channel
→ 回调业务逻辑。 - 解耦:网络 I/O(
epoll
/Connection
)和业务逻辑(Protocol
)分离,RegisterHandler
注册回调实现解耦。
(2)“智能指针与对象管理”
- 用
std::shared_ptr
管理Connection
/Channel
,自动管理内存,避免泄漏。 connections unorder map
:以fd
为键,保存所有客户端连接,方便根据fd
找到对应Connection
。
(3)“Listener 职责”
- 监听端口,收到新连接(
epoll
检测到EPOLLIN
)时,创建新的Connection
和Channel
,并加入epoll
监控。
多进程版 Reactor 负载均衡架构:
Master 监听新连接并通过管道通知 Slave,Slave 继承 listensocket 处理实际连接,用 “管道事件 + Reactor” 解耦进程间协作,解决多进程竞争新连接问题,适合多核高并发场景。
多 Reactor 模式的高并发 服务器架构 (了解)
主从 Reactor 分工:Master 负责 “接新连接 + 扔队列 + 发通知”,Slave 负责 “收通知 + 取连接 + 处理 I/O”,用 eventfd
实现高效跨线程通信,适合高并发服务器。核心是 负载均衡 + 事件驱动