C++ 仿 Muduo 库 #1:架构与 Reactor 模型解析
一、实现目标
本系列旨在通过 C++ 实现一个类似 Muduo 的高并发服务器组件。核心采用 One Thread One Loop 的主从 Reactor 模型,目标是提供一个简洁、高性能的基础设施。
通过这个组件,开发者可以快速搭建高性能的 TCP 或 HTTP 服务器。需要注意的是,当前项目定位为基础组件库,不包含具体业务逻辑,但预留了应用层协议(如 HTTP)的支持接口,方便后续扩展。
二、HTTP 服务器基础
HTTP 是运行在 TCP 之上的应用层协议,遵循简单的请求—响应模式。虽然 HTTP 服务器看起来只是处理文本数据,但其本质依然是 TCP 服务器。区别在于需要在应用层对数据进行格式化的组织与解析。
实现一个 HTTP 服务器的基本流程如下:
- 搭建 TCP 服务器接收客户端连接。
- 按照 HTTP 协议格式解析请求数据,明确客户端意图。
- 根据请求目的提供对应的服务处理。
- 将结果封装为 HTTP 响应格式发送回客户端。
当然,实现一个能跑通的 HTTP 服务器不难,难的是在高并发场景下保持高性能。这也是我们引入 Reactor 模式的初衷。
三、Reactor 模型详解
概念
Reactor 模式是一种事件驱动的处理模式。服务端程序利用 I/O 多路复用统一监听多个输入源,当有事件发生时,将其同步分派给对应的处理线程。它也被称为 Dispatcher 模式,是编写高性能网络服务器的核心技术之一。
简单来说,就是使用 I/O 多路复用统一监听事件,收到事件后分发给处理进程或线程。
分类
1. 单 Reactor 单线程
这种模式下,I/O 多路复用和业务处理都在同一个线程中完成。
- 流程:监控客户端请求 -> 触发事件 -> 处理(新建连接或数据处理)。
- 优点:串行化操作,逻辑简单,无需考虑线程间通信和资源竞争。
- 缺点:无法利用 CPU 多核资源,容易成为性能瓶颈。
- 适用:客户端数量少、处理速度快的场景。

2. 单 Reactor 多线程
为了解决 CPU 利用率问题,引入线程池处理业务。
- 流程:Reactor 线程负责 I/O 监控和连接建立;数据通信请求接收后,分发给 Worker 线程池处理;处理完毕后由 Reactor 线程发送响应。
- 优点:充分利用多核资源,降低耦合度。
- 缺点:多线程共享数据复杂;单个 Reactor 线程在高并发下可能成为瓶颈。

3. 多 Reactor 多线程(主从 Reactor)
这是 Muduo 等主流库采用的模型,进一步解决了单 Reactor 的瓶颈问题。
- 流程:
- 主 Reactor:专门处理新连接请求,将新连接分发到子 Reactor。
- 子 Reactor:负责已建立连接的 IO 事件监控,数据读取后分发给 Worker 线程池。
- Worker 线程池:执行具体的业务逻辑。
- 优点:职责分离,充分利用 CPU 资源。
- 注意:线程过多会增加上下文切换成本,需合理配置。

四、功能模块划分
整个架构由以下核心模块协作完成,它们共同支撑起高并发网络服务。
1. Buffer 模块
用于管理用户态的接收和发送缓冲区,屏蔽底层 Socket 读写的复杂性,提供高效的内存操作接口。
2. Socket 模块
封装了底层的套接字操作,包括创建、绑定、监听、连接等系统调用。
3. Channel 模块
描述符的事件管理器。它封装了文件描述符及其对应的事件(可读、可写、错误等),并在 Poller 就绪时回调相应的处理函数。
4. Connection 模块
这是通信的核心单元,封装了 Buffer、Socket、Channel 以及连接状态。
- 内部结构:包含接收/发送缓冲区、Socket 对象、Channel 对象。
- 回调机制:提供连接建立、事件触发、新数据到达、关闭连接等回调接口。
- 工作流程:
- 向 Channel 注册事件回调,并添加到 Poller 监控。
- 描述符就绪(如可读),Channel 调用读事件处理,将数据读入接收缓冲区。
- 触发新数据回调,由上层进行业务处理。
- 业务处理后,通过发送接口写入发送缓冲区。
- 启动写事件监控,就绪后将数据通过 Socket 发送出去。

5. Acceptor 模块
负责监听套接字的管理。它封装了 Socket 和 Channel,主要功能是获取新连接并构建 Connection 对象。
6. TimerQueue 模块
基于 Linux 的 timerfd 实现定时任务管理。主要用于非活跃连接的超时释放,管理连接的生命周期。
7. Poller 模块
对 epoll 的封装,负责 IO 事件的添加、修改、移除以及获取活跃连接列表。
8. EventLoop 模块
即 Reactor 的核心循环,保证'一个线程对应一个 EventLoop'。
- 线程安全:要求所有对 Connection 的操作必须在对应的 EventLoop 线程内完成。
- 内部组件:包含 Poller、TimerQueue、eventfd(用于唤醒阻塞)以及 PendingTask 队列。
- 工作流程:
- Poller 监控描述符事件,触发 Channel 回调。
- 处理完 IO 事件后,顺序执行任务队列中的操作。
- 利用 eventfd 防止 epoll 因无事件而长时间阻塞,确保任务能及时调度。

9. TcpServer 模块
对外暴露的服务器接口,整合了 Acceptor 和 EventLoop 线程池。
- 初始化:设置 BaseLoop,实例化 Acceptor 和 EventLoop 线程池。
- 连接处理:Acceptor 获取新连接后,创建 Connection 对象,分配 EventLoop,设置回调及定时销毁任务,并加入 Hash 表管理。
- 启动:启动 BaseLoop 进入事件循环。

10. 模块关系图
整体架构中各模块的交互关系如下所示:




