美文网首页
IO 多路复用(三)poll 函数

IO 多路复用(三)poll 函数

作者: Tubetrue01 | 来源:发表于2020-12-18 16:35 被阅读0次

引言

据说 poll 函数起源于 SVR3,最初局限于流设备。而到了 SVR4 取消了这种限制,允许 poll 工作在任何描述符上。 功能与 select 类似,不过在处理流设备时,它能够提供额外的信息。

1.0 函数原型

#include <sys/poll.h>

int poll(struct pollfd *fdarray, nfds_t nfds, int timeout);

1.1 参数

fdarray

该参数是指向一个结构数组第一个元素的指针。每个数组元素都是一个 pollfd 结构体,用于指定测试某个描述符 fd 的条件。我们看一下它的原型:

struct pollfd 
{
  int   fd;       /* descriptor to check */
  short events;   /* events of interest on fd */
  short revents;  /* events that occurred on fd */
};
  • fd 这个不用多说,就是描述符了。
  • events 就是我们关心的当前描述符的事件。
  • revents 函数把当前描述符的事件状态结果保存在该成员中。

这就理解为,把描述符、关心的事件、事件的状态封装成了一个对象。这些对象组成起来就构成了这个结构数组。它避免了像 select 函数中间三个参数都是值-结果参数。

说明

值-结果参数: 该参数在函数调用的时候作为值传递给函数,函数执行完毕之后将执行结果保存到该参数中,所谓一参两用。值-结果参数一定要传指针。

对于 events 跟 revents 参数,它们每一个都由指定某个特定条件的一位或多位构成,下面是一些常值:

常值 是否作为 events 的输入 是否作为 revents 结果 说明
POLLIN \bullet \bullet 普通或优先级带数据可读
POLLRDNORM \bullet \bullet 普通数据可读
POLLRDBAND \bullet \bullet 优先级带数据可读
POLLPRI \bullet \bullet 高优先级数据可读
POLLOUT \bullet \bullet 普通数据可写
POLLWRNORM \bullet \bullet 普通数据可写
POLLWRBAND \bullet \bullet 优先级带数据可写
POLLERR \circ \bullet 发生错误
POLLHUP \circ \bullet 发生挂起
POLLNVAL \circ \bullet 描述符不是一个打开的文件

我们需要记住 poll 识别三类数据:普通、优先级带、高优先级。

补充:

POLLIN 可被定义为 POLLRDNORM 和 POLLRDBAND 的逻辑或;POLLOUT 等同于 POLLWRNORM。

还要注意的是,如果是 TCP 和 UDP 套接字,一下的条件会引起 poll 返回特定的 revent (然而不性的是, POSIX 在其 poll 的定义中留了许多空洞,会造成多种方式可返回相同的条件)。

  • 所有正规 TCP 数据和所有 UDP 数据都被认为是普通数据。
  • TCP 的带外数据被认为是优先级带数据。
  • 当 TCP 连接的读半部分关闭时(譬如收到了一个来自对端的 FIN),也被认为是普通数据,随后的读操作将返回 0。
  • TCP 连接存在错误既可认为是普通数据,也可认为是错误(POLLERR)。无论哪种情况,随后的读操作将返回 -1,并把 errno 设置成合适的值。这可用于处理诸如接收到 RST 或发生超时等条件。
  • 在监听套接字上有新的连接可用既可认为是普通数据,也可认为是优先级数据。大多数实现视为普通数据。
  • 非阻塞式 connect 的完成被认为是使相应套接字可写。

nfds

该参数指定了结构数组(也就是第一个参数)中元素的个数。该参数被声明为:nfds_t 类型,对应的其实是:unsigned int。

timeout

该参数指定了 poll 函数返回前等待多长时间。

  • INFTIM
    永久等待。
  • 0
    立刻返回,不阻塞进程。
  • n
    指定等待毫秒数 n。

INFTIM 常值被定义为一个负值。如果系统不能提供毫秒级精度的定时器,该值就向上舍入到最接近的支持值。

补充:

POSIX 规范要求在头文件 <poll.h> 中定义 INFTIM,不过许多系统仍然把它定义在头文件 <sys/stropts.h> 中。

1.2 返回值

  • 0
    运行超时。
  • -1
    函数执行发生错误。
  • n
    已经就绪的描述符数量,即成员 revents 值非 0 的描述符数量。

如果不想关心某个描述符,只需要把该描述符对应的 pollfd 结构的 fd 成员设置成一个负值就可以了。poll 函数将会忽略这样的 pollfd 结构的 events 成员,并且返回时,将它的 revents 成员值置为 0。

2.0 注意

对于 poll 函数,就不再需要关心每个进程中最大描述符的数量之类的问题了,因为 poll 函数采用 pollfd 结构体数组的方式传递给内核,并且把传递数组元素的数量给内核的责任交给了调用者。所以,内核也就不在需要知道类似 fd_set 的固定大小的数据类型了。


参考

相关文章

网友评论

      本文标题:IO 多路复用(三)poll 函数

      本文链接:https://www.haomeiwen.com/subject/qvwxnktx.html