linux学习笔记(41)I/O复用函数——poll详解
摘要:poll与select的核心区别在于poll没有文件描述符数量限制(select最多1024个),且采用动态数组而非位图。poll使用pollfd结构体监听事件,包含fd、events和revents字段,通过位掩码设置多种事件类型(如POLLIN、POLLOUT)。poll函数参数包括文件描述符数组、元素个数和超时时间,返回活跃fd数量。相比select,poll无需计算maxfd,API
·
poll
poll vs select 核心区别
select就像老式电话总机:
- 接线员要记住所有电话号码
- 每次都要问:"1号?2号?3号?..."
- 最多只能记1024个号码
poll就像现代呼叫系统:
- 系统自动记录所有房间号
- 哪个房间按铃,灯就亮
- 没有数量限制
poll的基本结构
poll的核心数据结构
#include <poll.h>
struct pollfd {
int fd; // 文件描述符
short events; // 要监听的事件
short revents; // 实际发生的事件
};
poll函数
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数说明
fd:
- 要监听的文件描述符。
- 如果 fd = -1,则 poll 会忽略这个结构体(不监听)。
events(要监听的事件,位掩码):
- POLLIN:有数据可读(包括普通数据、优先级数据)
- POLLPRI:有紧急数据可读(比如 TCP 带外数据)
- POLLOUT:可以写数据(内核发送缓冲区未满)
- POLLERR:错误(只作为输出事件,不需要设置)
- POLLHUP:挂起(比如管道写端关闭)
- POLLNVAL:fd 无效
revents(返回的事件):
- poll 返回时,内核会在这里标记实际发生的事件。
- 可能包含 POLLIN、POLLOUT、POLLERR 等。
(2) nfds —— 数组元素个数
- 类型是 nfds_t(实际上就是 unsigned int)
- 告诉 poll 数组 fds 里有多少个元素需要监听
(3) timeout —— 超时时间(毫秒)
- timeout > 0:最多等待 timeout 毫秒后返回
- timeout == 0:立即返回,不阻塞(轮询)
- timeout == -1:一直阻塞,直到有事件发生或被信号中断
返回值
- > 0:有事件发生的文件描述符数量
- == 0:超时,没有事件发生
- == -1:出错,errno 会说明原因(如被信号中断 EINTR)
使用步骤
- 定义 struct pollfd 数组,设置每个 fd 要监听的事件
- 调用 poll 等待事件
- 遍历数组,检查 revents 看哪些 fd 有事件
3. 从select迁移到poll
3.1 先看select的写法(复习)
// select的方式
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
FD_SET(client1, &readfds);
select(maxfd+1, &readfds, NULL, NULL, NULL);
if (FD_ISSET(sockfd, &readfds)) {
// 处理新连接
}
if (FD_ISSET(client1, &readfds)) {
// 处理客户端数据
}
3.2 同样的功能用poll实现
// poll的方式
struct pollfd fds[2];
fds[0].fd = sockfd; // 服务器socket
fds[0].events = POLLIN; // 监听读事件
fds[1].fd = client1; // 客户端socket
fds[1].events = POLLIN; // 监听读事件
int n = poll(fds, 2, -1); // 监听2个fd,无限等待
if (fds[0].revents & POLLIN) {
// 处理新连接
}
if (fds[1].revents & POLLIN) {
// 处理客户端数据
}
poll的事件类型
// 常用的事件类型
POLLIN // 数据可读
POLLOUT // 数据可写
POLLERR // 发生错误
POLLHUP // 连接挂断
POLLNVAL // 无效的fd
// 组合使用
fds[i].events = POLLIN | POLLOUT; // 同时监听读和写
// 检查多个事件
if (fds[i].revents & (POLLIN | POLLERR)) {
// 有数据可读或发生错误
}
// 在头文件 poll.h 中定义:
#define POLLIN 0x001 // 二进制: 0000 0000 0001
#define POLLOUT 0x004 // 二进制: 0000 0000 0100
#define POLLERR 0x008 // 二进制: 0000 0000 1000
#define POLLHUP 0x010 // 二进制: 0000 0001 0000
// 可以同时监听多个事件
fds[i].events = POLLIN | POLLOUT;
// 相当于: 0x001 | 0x004 = 0x005
// 二进制: 0000 0000 0101 (同时设置了第1位和第3位)
// 当事件发生时,内核会设置相应的位
// 比如同时有数据可读和可写:
fds[i].revents = POLLIN | POLLOUT; // 0x005
// 例子1:检查是否有POLLIN事件
fds[i].revents = 0x005; // 二进制: 0000 0000 0101 (有POLLIN和POLLOUT)
POLLIN = 0x001; // 二进制: 0000 0000 0001
0x005 & 0x001 = 0x001 // 结果不为0 → 有POLLIN事件
// 例子2:检查是否有POLLERR事件
fds[i].revents = 0x005; // 二进制: 0000 0000 0101
POLLERR = 0x008; // 二进制: 0000 0000 1000
0x005 & 0x008 = 0x000 // 结果为0 → 没有POLLERR事件
|
特性
|
select
|
poll
|
|
最大fd数
|
1024
|
无限制
|
|
效率
|
O(n)扫描
|
O(n)扫描
|
|
内存使用
|
固定位图
|
动态数组
|
|
平台支持
|
所有Unix
|
大部分Unix
|
|
使用难度
|
简单
|
简单
|
poll的优点
- 没有fd数量限制(select只有1024)
- 不需要计算maxfd+1
- 事件类型更丰富
- API更直观
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)