Poll 函数原理与 TCP 服务器实现详解
select 作为早期 I/O 多路复用技术,存在文件描述符数量上限和参数耦合两个核心缺陷。poll 函数针对这些问题做了改进,突破 fd 限制并分离输入输出参数,但轮询本质未变。
一、Poll 函数核心解析
poll 的功能与 select 一致:监视并等待多个文件描述符的状态变化。区别在于管理方式更灵活。
1.1 核心参数:struct pollfd 数组
select 使用位图(fd_set)管理 fd,而 poll 通过 pollfd 结构体数组管理,每个结构体对应一个待监视的 fd 及其事件。
pollfd 结构体定义
struct pollfd {
int fd; // 待监视的文件描述符
short events; // 输入参数:用户要监视的事件(位掩码)
short revents; // 输出参数:内核返回的就绪事件(位掩码)
};
关键事件宏定义
events(输入)和 revents(输出)均通过位掩码表示事件,支持多种事件的组合(用 | 运算符)。
| 事件宏 | 含义(events 输入 /revents 输出) | 对应 select 功能 |
|---|---|---|
| POLLIN | 有数据可读(普通 / 优先数据) | 读事件(FD_SET 读集合) |
| POLLOUT | 写操作不会阻塞(普通 / 优先数据) | 写事件(FD_SET 写集合) |
| POLLERR | 输出专属:fd 发生错误 | 异常事件 |
| POLLHUP | 输出专属:fd 发生挂起(如客户端断开连接) | 异常事件 |
| POLLNVAL | 输出专属:fd 非法(如未打开) | 异常事件 |
使用规则:
- events 仅能设置'输入事件'(如 POLLIN、POLLOUT),设置 POLLERR 等输出事件无意义;
- revents 由内核填充,可能包含 events 中的事件,也可能包含 POLLERR 等异常事件;
- 事件判断示例:判断 fd 是否可读,需检查
revents & POLLIN(非 0 则就绪)。
1.2 参数二:nfds(数组大小)
nfds 表示 pollfd 数组中有效元素的数量,告诉内核需要遍历的结构体数量,避免访问越界。
1.3 参数三:timeout(超时时间)
timeout 指定 poll 的阻塞时长,单位为毫秒,是纯输入参数。
| timeout 取值 | 含义 |
|---|---|
| -1 | 无限阻塞,直到有 fd 就绪或被信号中断 |
| 0 | 非阻塞模式,立即返回 |
| >0 |


