11_Reactor网络模型
一、Reactor模型基本原理
Reactor模型是一种基于事件驱动的设计模式,特别适合处理高并发的I/O密集型应用。

Reactor模型的核心思想很简单,但又很巧妙,它围绕着"事件"展开。不同于传统模型中线程主动等待I/O完成,Reactor模型采用了完全不同的思路:
- 有一个事件分离器(通常是I/O多路复用技术如select、poll或epoll)监听所有连接上的事件;
- 当有事件发生时,事件分离器通知事件处理器;
- 事件处理器负责处理对应的事件,如接受新连接、读数据、写数据等;
- 所有操作都在事件循环中进行,无需阻塞等待。
这种设计的最大特点是:单线程可以处理多个连接,而且只在有事件发生时才会处理,极大地提高了CPU利用率。
Reactor模型的核心组件:
- 事件源(Event Source):产生事件的对象,如socket连接
- 事件多路分离器(Event Demultiplexer):I/O多路复用机制,如select/poll/epoll
- 事件分发器(Dispatcher):将事件分发给对应的处理器
- 事件处理器(Event Handler):具体处理不同类型事件的逻辑
优点:
- 高效处理I/O:避免了阻塞等待,一个线程可以处理多个连接
- 可扩展性好:可以根据需要增加Reactor线程数量
- 编程模型清晰:基于事件驱动,职责分明
缺点:
- 复杂性:比传统模型复杂,调试也更困难
- 对长时间操作不友好:如果某个事件处理器占用太长时间,会阻塞其他事件的处理
运用场景:
- 高并发场景:当需要同时处理成千上万个连接时
- I/O密集型应用:如Web服务器、代理服务器、消息中间件等
- 实时性要求高:需要快速响应客户端请求
用一段伪代码来表示Reactor模型的基本工作流程:
// Reactor主循环
while (true) {
// 使用I/O多路复用等待事件发生
events = demultiplexer.wait();
// 遍历所有就绪的事件
for (event in events) {
// 根据事件类型,调用对应的处理函数
switch (event.type) {
case ACCEPT:
handleAccept(event);
break;
case READ:
handleRead(event);
break;
case WRITE:
handleWrite(event);
break;
case CLOSE:
handleClose(event);
break;
}
}
}
// 处理新连接
function handleAccept(event) {
// 接受新连接
newConnection = accept(event.fd);
// 设置新连接为非阻塞
setNonBlocking(newConnection);
// 注册读事件处理器,等待客户端发送数据
demultiplexer.register(newConnection, READ, handleRead);
}
// 处理读事件
function handleRead(event) {
// 读取数据
data = read(event.fd);
if (data.length > 0) {
// 处理请求
response = processRequest(data);
// 注册写事件处理器,准备发送响应
demultiplexer.register(event.fd, WRITE, handleWrite);
// 保存响应数据,供写事件处理器使用
connections[event.fd].response = response;
} else {
// 客户端关闭连接
handleClose(event);
}
}
// 处理写事件
function handleWrite(event) {
// 获取要发送的响应数据
response = connections[event.fd].response;
// 发送数据
write(event.fd, response);
// 再次注册读事件处理器,等待客户端的下一个请求
demultiplexer.register(event.fd, READ, handleRead);
}
// 处理关闭连接
function handleClose(event) {
// 从demultiplexer中移除
demultiplexer.unregister(event.fd);
// 关闭连接
close(event.fd);
// 清理相关资源
delete connections[event.fd];
}
二、Reactor模型的三种实现方式
随着服务器要处理的连接数增多,单线程Reactor模式可能会成为瓶颈。因此,Reactor模型有三种常见的实现方式。
2.1 单Reactor单线程模型

单Reactor单线程模型是最简单的实现,所有工作都在同一个线程中完成:
- Reactor线程负责监听连接、接受连接、读写数据和处理业务逻辑
- 优点是简单,没有并发问题
- 缺点是无法充分利用多核CPU,业务处理复杂时会造成整个服务阻塞
适用场景:连接数少且业务处理简单的场景,如Redis在单线程模式下的运行方式。
2.2 单Reactor多线程模型

单Reactor多线程模型相比单线程模型有了明显改进:
- Reactor线程负责监听连接、接受连接和读写数据
- 业务处理放在线程池中进行,避免了业务处理阻塞网络I/O
- 优点是能够充分利用多核CPU,提高处理能力
缺点:
- Reactor线程仍然是瓶颈,连接数量达到一定程度后,单个Reactor线程可能无法处理所有的I/O事件,导致性能下降
- 多线程间共享数据需要考虑并发问题,增加了编程复杂度
2.3 主从Reactor多线程模型

主从Reactor多线程模型是三种模式中最强大的一种,也是目前主流高性能服务器采用的模型:
- 主Reactor线程:只负责监听连接和接受新连接,然后将新连接分发给从Reactor线程
- 从Reactor线程:负责处理已连接的socket上的读写事件
- 业务线程池:负责执行具体业务逻辑,完全与网络I/O分离
优点:
- 职责分明:主Reactor只负责接受连接,从Reactor只负责I/O,业务线程只负责处理业务逻辑
- 可扩展性强:可以根据需要调整从Reactor和业务线程的数量
- 减轻了主Reactor的负担:避免了单Reactor的性能瓶颈
- 充分利用多核:不同Reactor和业务线程可以运行在不同的CPU核心上
三、Reactor模型的实际应用
基于Reactor模式的TCP服务器:
#include <iostream>
#include <vector>
#include <map>
#include <functional>
#include <memory>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
// 事件处理器基类
class EventHandler {
public:
EventHandler(int fd) : fd_(fd) {}
virtual ~EventHandler() = default;
virtual void handleRead() = 0;
virtual void handleWrite() = 0;
int getFd() const { return fd_; }
protected:
int fd_;
};
// Reactor类
class Reactor {
public:
Reactor() {
// 创建epoll实例
epoll_fd_ = epoll_create1(0);
if (epoll_fd_ == -1) {
std::cerr << "Failed to create epoll instance" << std::endl;
exit(EXIT_FAILURE);
}
}
~Reactor() {
if (epoll_fd_ != -1) {
close(epoll_fd_);
}
}
// 注册事件处理器
void registerHandler(std::shared_ptr<EventHandler> handler, uint32_t events) {
struct epoll_event ev;
ev.events = events;
ev.data.fd = handler->getFd();
if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, handler->getFd(), &ev) == -1) {
std::cerr << "Failed to add fd to epoll" << std::endl;
return;
}
handlers_[handler->getFd()] = handler;
}
// 修改事件
void modifyHandler(std::shared_ptr<EventHandler> handler, uint32_t events) {
struct epoll_event ev;
ev.events = events;
ev.data.fd = handler->getFd();
if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, handler->getFd(), &ev) == -1) {
std::cerr << "Failed to modify fd in epoll" << std::endl;
return;
}
}
// 移除事件处理器
void removeHandler(std::shared_ptr<EventHandler> handler) {
epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, handler->getFd(), nullptr);
handlers_.erase(handler->getFd());
}
// 事件循环
void eventLoop() {
const int MAX_EVENTS = 10;
struct epoll_event events[MAX_EVENTS];
while (true) {
int nfds = epoll_wait(epoll_fd_, events, MAX_EVENTS, -1);
if (nfds == -1) {
std::cerr << "epoll_wait error" << std::endl;
break;
}
for (int i = 0; i < nfds; i++) {
int fd = events[i].data.fd;
auto it = handlers_.find(fd);
if (it != handlers_.end()) {
if (events[i].events & EPOLLIN) {
it->second->handleRead();
}
if (events[i].events & EPOLLOUT) {
it->second->handleWrite();
}
}
}
}
}
private:
int epoll_fd_;
std::map<int, std::shared_ptr<EventHandler>> handlers_;
};
// 工具函数,设置socket为非阻塞
void setNonBlocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
// 接受连接处理器
class AcceptorHandler : public EventHandler {
public:
AcceptorHandler(int port, Reactor& reactor)
: EventHandler(-1), reactor_(reactor) {
// 创建监听socket
fd_ = socket(AF_INET, SOCK_STREAM, 0);
if (fd_ < 0) {
std::cerr << "Failed to create socket" << std::endl;
exit(EXIT_FAILURE);
}
// 允许地址复用
int opt = 1;
setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// 绑定地址
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (bind(fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
std::cerr << "Failed to bind" << std::endl;
exit(EXIT_FAILURE);
}
// 监听
if (listen(fd_, SOMAXCONN) < 0) {
std::cerr << "Failed to listen" << std::endl;
exit(EXIT_FAILURE);
}
setNonBlocking(fd_);
std::cout << "Server listening on port " << port << std::endl;
}
~AcceptorHandler() {
if (fd_ >= 0) {
close(fd_);
}
}
void handleRead() override {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_fd = accept(fd_, (struct sockaddr*)&client_addr, &client_len);
if (client_fd < 0) {
std::cerr << "Failed to accept" << std::endl;
return;
}
setNonBlocking(client_fd);
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));
std::cout << "New connection from " << client_ip << ":" << ntohs(client_addr.sin_port) << std::endl;
// 创建连接处理器
auto handler = std::make_shared<ConnectionHandler>(client_fd, reactor_);
reactor_.registerHandler(handler, EPOLLIN | EPOLLET);
}
void handleWrite() override {
// 作为接受器,不需要处理写事件
}
private:
Reactor& reactor_;
};
// 连接处理器
class ConnectionHandler : public EventHandler {
public:
ConnectionHandler(int client_fd, Reactor& reactor)
: EventHandler(client_fd), reactor_(reactor), write_ready_(false) {
}
~ConnectionHandler() {
if (fd_ >= 0) {
close(fd_);
}
}
void handleRead() override {
char buffer[1024];
ssize_t n;
while ((n = read(fd_, buffer, sizeof(buffer))) > 0) {
buffer[n] = '\0';
write_buffer_ += buffer;
}
if (n == 0) {
// 客户端关闭连接
std::cout << "Connection closed" << std::endl;
reactor_.removeHandler(shared_from_this());
return;
} else if (n < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 读取完毕
if (!write_buffer_.empty()) {
// 准备写入响应
write_ready_ = true;
reactor_.modifyHandler(shared_from_this(), EPOLLIN | EPOLLOUT | EPOLLET);
}
} else {
std::cerr << "Read error" << std::endl;
reactor_.removeHandler(shared_from_this());
}
}
}
void handleWrite() override {
if (!write_ready_) {
return;
}
ssize_t n = write(fd_, write_buffer_.c_str(), write_buffer_.size());
if (n < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// 稍后再试
return;
}
std::cerr << "Write error" << std::endl;
reactor_.removeHandler(shared_from_this());
return;
}
// 写入完成
write_buffer_.clear();
write_ready_ = false;
// 修改为只关注读事件
reactor_.modifyHandler(shared_from_this(), EPOLLIN | EPOLLET);
}
private:
Reactor& reactor_;
std::string write_buffer_;
bool write_ready_;
};
int main() {
Reactor reactor;
// 创建接受器,监听8888端口
auto acceptor = std::make_shared<AcceptorHandler>(8888, reactor);
reactor.registerHandler(acceptor, EPOLLIN);
// 启动事件循环
reactor.eventLoop();
return 0;
}
Reactor模式的核心思想:
- Reactor类:实现了事件循环,负责监听事件和分发事件
- EventHandler基类:提供了事件处理的接口
- AcceptorHandler:处理连接事件
- ConnectionHandler:处理已建立连接的读写事件
这是单Reactor单线程模型的实现。虽然简单,但已经能看出Reactor模式的优势,能够利用一个线程处理多个客户端连接,避免了传统的一连接一线程模型的资源浪费。
如果要实现主从Reactor多线程模型,我们需要:
- 创建一个主Reactor线程,专门负责接受连接
- 创建多个从Reactor线程,处理读写事件
- 创建业务线程池,处理具体业务逻辑

浙公网安备 33010602011771号