epoll 事件全集、每个事件的含义、哪些事件在实际服务器中最常见、哪些会组合出现

一、epoll 事件总览(最常用的 10 个)

epoll 返回的 events 是一个 bitmask(位图),可能包含多个事件组合。

下面按使用频率从高到低列出来:

事件名 含义 是否常见
EPOLLIN fd 可读(有数据到达 / 对端关闭) ★★★★★
EPOLLOUT fd 可写(发送缓冲区有空位置) ★★★★
EPOLLERR socket 出错(RST 等) ★★★★★
EPOLLHUP 对端关闭(FIN) ★★★★★
EPOLLRDHUP 半关闭(对方调用了 shutdown(SHUT_WR)) ★★★★
EPOLLET 边缘触发模式 ★★★★★(高性能服务器必须用)
EPOLLONESHOT 一次性事件,处理完需手动重置 ★★★★
EPOLLPRI 紧急数据(TCP OOB) ★★
EPOLLEXCLUSIVE 避免惊群(监听 socket 用) ★★★
EPOLLWAKEUP 系统唤醒(安卓) 少见

二、最常见 & 必须处理的事件组合

epoll 最典型的 four events:

复制代码
EPOLLIN     → 有数据可读
EPOLLOUT    → 可以写数据
EPOLLERR    → 错误,必须关闭
EPOLLHUP    → 对方挂断,必须关闭

大多数情况下会处理的就是这四个。

三、事件组合出现的情况(epoll 特点)

epoll 一次返回的 events 可能包含多个标志位,例如:

1. 正常收发数据:

复制代码
events = EPOLLIN

2. 写入数据阻塞后,现在可写:

复制代码
events = EPOLLOUT

3. 对端关闭 + 有未读完的数据:

复制代码
events = EPOLLIN | EPOLLRDHUP

4. 错误 + 可读(错误最高优先级)

复制代码
events = EPOLLIN | EPOLLERR

5. 边缘触发写法常见:

复制代码
events = EPOLLIN | EPOLLOUT | EPOLLET

四、生产服务器具体会遇到哪些组合?

实际开发中出现频率最高的组合如下:

① 客户端发送数据 → 服务器读事件:

复制代码
EPOLLIN

② 客户端断开 → 两种情况:

正常断开:

复制代码
EPOLLHUP | EPOLLIN

异常断开:

复制代码
EPOLLERR

半关闭(常见于 HTTP/1.1):

复制代码
EPOLLIN | EPOLLRDHUP

③ 写缓冲区满后又能写了:

复制代码
EPOLLOUT

④ 边缘触发(ET)+ 写事件:

复制代码
EPOLLIN | EPOLLET

⑤ epoll 已经出错:

复制代码
EPOLLERR

这种必须马上 close。

五、事件含义详细讲解

EPOLLIN(最常见)

  • 套接字可读

  • read() 不会阻塞

  • 包含:对端关闭时 read=0 也会触发 IN

EPOLLOUT

  • 套接字可写

  • send() 不会阻塞

EPOLLERR(非常关键)

  • 底层 TCP 出错(如对方 RST)

  • 必须马上关闭 fd

  • 如果不处理,会造成 CPU 100%

EPOLLHUP(非常关键)

  • 对端关闭(FIN)

  • 必须关闭 fd,不要再读写

EPOLLRDHUP(高质量服务器必须用)

  • 对端半关闭(如 shutdown)

  • HTTP keep-alive 场景很常见

  • 比 EPOLLHUP 更准确

EPOLLET:边缘触发

  • 高性能服务器必用(比如 nginx)

  • 必须一次性读完所有数据,否则不会再触发

EPOLLONESHOT:一次性事件

  • 用于多线程模型,防止多个线程抢同一个 fd

六、一个真实服务器事件判断模板

cpp 复制代码
uint32_t ev = events;

// 优先处理错误
if (ev & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
    closeConn(fd);
    return;
}

// 可读事件
if (ev & EPOLLIN) {
    handleRead(fd);
}

// 可写事件
if (ev & EPOLLOUT) {
    handleWrite(fd);
}

这就是 nginx、muduo、libevent 的标准写法。

相关推荐
fpcc17 小时前
c++编程实践—堆和栈越界调试
c++
_upupup18 小时前
Linux的调试工具——gdb/cgdb
linux·服务器
JeJe同学18 小时前
Docker镜像导入、容器启动
linux·运维·docker
Jason_zhao_MR18 小时前
Linux与实时控制如何兼得
linux·嵌入式硬件·机器人·工业控制
weiabc19 小时前
MSYS2 UCRT64 + g++ C++ 中文输出乱码 完整全过程
c++
闲云野鹤在人间19 小时前
MySQL|从理论、安装、备份到主从复制、MHA高可用详解
linux·运维·数据库·mysql·云计算
灯澜忆梦20 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
一个风轻云淡20 小时前
GCC 和 GDB命令简单解读
java·linux·前端
H.莓飛20 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
资料库0120 小时前
Linux 8个常见运维故障排查
java·linux·运维