ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

IO——poll 函数

2026/9/12 19:58:43 拓冰建站 浏览量
IO——poll 函数

文章目录

    • 函数原型
      • fds
      • nfds
      • timeout
      • 返回值
    • IO 流程
    • 使用示例

在单个线程中,select 函数能够监视的文件描述符数量有最大的限制,一般为 1024,可以修改内核将监视的文件描述符数量改大,但是这样会降低效率!

这个时候就可以使用 poll 函数,poll 函数本质上和 select 没有太大的差别,但是 poll 函数没有最大文件描述符限制,

函数原型

linux 应用程序中 poll 函数原型如下所示

#include<poll.h>int poll(struct poll_fd *fds, nfds_t  nfds, int timeout)

fds

要监视的文件描述符集合以及要监视的事件,为一个数组,数组元素都是结构体 struct pollfd 类型

// pollfd结构
struct pollfd {int fd;           /* 要监听的fd  */short int events; /* 要监听的事件类型:读、写、异常 */short int revents;/* 实际发生的事件类型 */
};
  • fd 文件描述符,如果 fd 无效的话,那么 events 监视事件也就无效,并且 revents 返回 0
  • events 要监视的事件,可监视的事件类型如下所示
事件描述是否可作为输入(events)是否可作为输出(revents)
POLLIN数据可读
POLLOUT数据可写
POLLPRI高优先级数据可读
POLLRDNORM普通数据可读
POLLERR指定的文件描述符发送错误
POLLNVAL无效的请求
  • revents 返回的事件,由 linux 内核设置具体的返回事件

nfds

poll 函数要监视的文件描述符数量

timeout

timeout表示超时时间(以毫秒为单位)。

返回值

返回 revents 域中不为 0 的 pollfd 结构体个数,也就是发生事件或错误的文件描述符数量;0,超时;-1,发生错误,并且设置 errno 为错误类型

IO 流程

  • 创建pollfd数组,向其中添加关注的fd信息,数组大小自定义
  • 调用poll函数,将pollfd数组拷贝到内核空间,转链表存储,无上限
  • 内核遍历fd,判断是否就绪
  • 数据就绪或超时后,拷贝pollfd数组到用户空间,返回就绪fd数量n
  • 用户进程判断n是否大于0
  • 大于0则遍历pollfd数组,找到就绪的fd
    通过上述流程,我们发现相对于select,poll有了两点改变:

1、select模式中的fd_set大小固定为1024,而pollfd在内核中采用链表,理论上无上限
2、监听FD越多(fd_set越大),每次遍历消耗时间也越久,性能反而会下降

虽然poll解决了select中监听fd的上限,但是poll中还是要遍历所有的FD,且如果fd监听过多会导致性能下降。

使用示例

#define NFDS 100void DealFinishFd(struct pollfd *fds)
{for (unsigned int i = 0; i < NFDS; i++){if (fds[i].fd == -1){continue;}if (fds[i].revents & POLLIN){}else if (fds[i].revents & POLLRDHUP){}else if (fds[i].revents & POLLIN){}}
}int main(void)
{struct pollfd *fds = (struct pollfd *)malloc(sizeof(struct pollfd) * NFDS);assert(NULL != fds);InitFds(fds);while (1){int n = poll(fds, NFDS, -1);if (n <= 0){printf("poll error\n");continue;}DealFinishFd(fds);}free(fds);
}