
在 Linux 环境中,reactor 指的是一种基于 I/O 多路复用的事件驱动设计模式,其核心思想是通过一个专门的组件(反应器)监听多个 I/O 事件(如网络连接、数据读写等),当事件发生时触发对应的回调函数进行处理,从而让单个进程或线程能高效处理大量并发连接,避免传统阻塞 I/O 中因等待而造成的资源浪费。它通常依赖 Linux 的 select、poll 或 epoll 等系统调用来实现事件监听,常见于高性能网络服务器开发,比如通过 libevent、libev 等库来快速构建基于 reactor 模式的应用,以应对高并发场景下的 I/O 处理需求。在多进程线程中,write更简单。LT:只要可写就持续通知,有剩余空间ET:仅在缓冲区从满变为不满时通知一次把一个sockfd托管给select,poll,epoll原因是因为sockfd上事件没有就绪,用托管来提高效率。默认sockfd新建的情况下,读事件默认不是就绪的,因为输入缓冲区没有数据,所以默认添加epoll。而写事件是就绪的,因为输出缓冲区本来就有空间,所以,在前期,我们可以直接写,但是到了后期输出缓冲区可能会满,那时才需要epoll监听。对于写,我们直接发,发送条件不满足,开启写事件关心,后续剩余的数据,epoll会协助我自动进行发送。补充细节:1.如果我们开头直接对一个sockfd设置写关心,epoll就会立即就绪。2.未来我全部发完了,就要对关闭这个fd写事件关心3.如果写缓冲区没满,数据也发完了,我们就不用开启对写事件关心。4.直接发,我怎么知道写入条件不满足了呢,errno是EAGAIN即可。所以,对写事件关心最好是ET非阻塞。LT阻塞根本发挥不了作用,LT非阻塞与ET差不多。以上是用单进程+epoll+非阻塞实现的,下面是加入多线程和多进程的思路。主reactor线程+工作者线程池#include sys/epoll.h #include pthread.h #include fcntl.h #include unistd.h // 线程安全的任务队列 struct task_queue_t { // ... 使用互斥锁(pthread_mutex_t)和条件变量(pthread_cond_t)实现 }; void* reactor_thread(void* arg) { int epoll_fd = epoll_create1(0); int listen_fd; // 已初始化的监听socket struct epoll_event event, events[MAX_EVENTS]; // 将listen_fd加入epoll event.events = EPOLLIN; event.data.fd = listen_fd; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, event); while (1) { int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); for (int i = 0; i nfds; ++i) { if (events[i].data.fd == listen_fd) { // 处理新连接 int conn_fd = accept4(listen_fd, NULL, NULL, SOCK_NONBLOCK); event.events = EPOLLIN | EPOLLET; // 边缘触发模式 event.data.fd = conn_fd; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, event); } else if (events[i].events EPOLLIN) { // 数据可读 int conn_fd = events[i].data.fd; char buffer[BUFFER_SIZE]; ssize_t count = read(conn_fd, buffer, BUFFER_SIZE); if (count 0) { // 封装任务,推送给工作者线程池 task_t* task = create_task(conn_fd, buffer, count); task_queue_push(global_task_queue, task); } } // ... 处理 EPOLLOUT, EPOLLHUP 等事件 } } } void* worker_threa