Reactor模式是一种基于事件驱动的应用程序组织模型,符合IoC(控制反转)思想:
其核心思想是:
class EventHandler {
virtual void handleRead() {}
virtual void handleWrite() {}
virtual void handleError() {}
};
这是策略模式的应用,不同类型的事件有不同的处理策略。
这是Reactor的核心,负责:
专门处理新连接的建立,体现了单一职责原则。
对比:
特性 | 传统多线程 | Reactor模式 |
---|---|---|
线程数量 | 每连接一线程单线程 | 处理所有连接 |
内存消耗 | 高(每线程~8MB栈) | 低 |
上下文切换 | 频繁 | 无 |
同步问题 | 复杂(锁、条件变量) | 简单 |
扩展性 | 受线程数限制 | 受单机性能限制 |
优势:
适用场景:
详见 TCP/IP 网络编程 | IO多路复用select/poll/epoll
含具体代码
epoll
是Linux上最高效的IO多路处理技术,目前基本可看作select/poll的升级版本。
// 创建epoll实例
int epoll_create1(int flags);
// 控制epoll行为
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
// op: EPOLL_CTL_ADD, EPOLL_CTL_MOD, EPOLL_CTL_DEL
// 等待事件
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
关键API:
epoll_create
:创建epoll对象epoll_ctl
:将fd注册到epoll对象epoll_wait
:等待事件发生epoll_event结构体:
struct epoll_event {
uint32_t events; // 事件类型
epoll_data_t data; // 用户数据
};
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
epoll_event {uint32_t events; void* data;}
// 特点:只在状态变化时触发一次
// 优点:性能更高,系统调用更少
// 缺点:必须一次性处理完所有数据
while (true) {
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
for (int i = 0; i < n; i++) {
if (events[i].events & EPOLLIN) {
// 必须循环读取直到EAGAIN
while (true) {
char buf[1024];
int ret = read(events[i].data.fd, buf, 1024);
if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
break; // 数据读完了
}
// 处理错误
} else if (ret == 0) {
// 连接关闭
break;
}
// 处理数据
}
}
}
}
// 特点:只要条件满足就持续触发
// 优点:编程简单,不容易丢失事件
// 缺点:可能产生多余的系统调用
while (true) {
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
for (int i = 0; i < n; i++) {
if (events[i].events & EPOLLIN) {
// 即使只读取部分数据,下次epoll_wait仍会返回该事件
char buf[100];
read(events[i].data.fd, buf, 100);
}
}
}
Reactor模式体现在Linux中,就是一个主循环用 epoll_wait
加上各类fd的处理器:
+------------------+
| Reactor |
| epoll_wait()、分发 |
+------------------+
|
+--------+--------+
| |
+--------v-----+ +------v--------+
| AcceptHandler| | IOHandler |
| (接口连接) | | (读写数据) |
+--------------+ +---------------+
EventHandler基类
class EventHandler {
public:
virtual ~EventHandler() = default;
virtual void handleRead() {} // 可读事件处理
virtual void handleWrite() {} // 可写事件处理
virtual void handleError() {} // 错误事件处理
virtual int getFd() const = 0; // 获取文件描述符
};
EventLoop核心实现
class EventLoop {
private:
int epollFd_; // epoll文件描述符
std::unordered_map<int, std::shared_ptr<EventHandler>> handlers_; // fd到处理器的映射
bool running_; // 运行状态
public:
void addEvent(int fd, EventType events, std::shared_ptr<EventHandler> handler);
void modifyEvent(int fd, EventType events);
void removeEvent(int fd);
void run(); // 主事件循环
};
非阻塞设置
// 将socket设置为非阻塞模式
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
边缘触发的正确处理
void ConnectionHandler::handleRead() override {
char buffer[1024];
ssize_t n = read(fd_, buffer, sizeof(buffer));
if (n > 0) {
// 处理数据
} else if (n == 0) {
// 连接关闭
} else {
// n < 0
if (errno != EAGAIN && errno != EWOULDBLOCK) {
// 真正的错误
handleError();
}
// EAGAIN表示暂时没有数据,正常情况
}
}