poll 函数
poll
提供的功能与select
类似,不过在处理流设备时,它能够提供额外的信息。
1 |
|
第一个参数是指向一个结构数组第一个元素的指针。每个数组元素都是一个pollfd
结构,用于指定测试某个给定描述符fd
的条件。
1 | struct pollfd { |
要测试的条件由events
成员指定,函数在相应的revents
成员中返回该描述符的状态。这两个成员中的每一个都由指定的某个特定条件的一位或多位构成。用于指定events
标志以及测试revents
标志的一些常值。
- POLLIN: 普通或优先级数据可读
- POLLRDNORM: 普通数据可读
- POLLRDBAND: 优先级带数据可读
- POLLPRI: 高优先级数据可读
- POLLOUT: 普通数据可写
- POLLWRNORM: 普通数据可写
- POLLWRBAND:优先级带数据可写
- POLLERR:发生错误
- POLLHUP:发生挂起
- POLLNVAL:描述符不是一个打开的文件
POLLERR
、POLLHUP
、POLLNVAL
这三个常值不能再events
中设置,但是当相应条件存在时就在revents
中返回。
POLLIN
可被定义为POLLRDNORM
和POLLRDBAND
的逻辑或。POLLOUT
等同于POLLWRNORM
就TCP和UDP套接字而言,以下条件引起poll
返回特定的revent
。
- 所有正规TCP数据和所有UDP数据都被认为是普通的数据。
- TCP的带外数据被认为是优先级带数据。
- 当TCP连接的读半部关闭时(譬如收到了一个来自对端的 FIN ),也被认为是普通数据。随后的读操作将返回0。
- TCP连接存在错误既可认为是普通数据,也可认为是错误(
POLLERR
)。无论哪种情况,随后的读操作将返回-1,并把errno
设置成合适的值。这可用于处理诸如接收到 RST 或发生超时等条件。 - 在监听套接字上有新的连接可用既可认为是普通数据,也可认为是优先级数据。大多数实现视为普通数据。
- 非阻塞式
connect
的完成被认为是使相应套接字可写。
结构数组中元素的个数是由nfds
参数指定。
timeout
参数指定poll
函数返回前等待多长时间。它是一个指定应等待毫秒数的正值。INFTIM
表示永远等待。0立即返回,不阻塞进程。大于0等待指定数目的毫秒数。
INFTIM
常值被定义为一个负值。
当发生错误时,poll
函数的返回值为-1,若定时器到时之前没有任何描述符就绪,则返回0,否则返回就绪描述符的个数,即revents
成员值非0的描述符个数。
如果我们不再关心某个特定描述符,那么可以把与它对应的pollfd
结构的fd成员设置成一个负值。poll
函数将忽略这样的pollfd
结构的events
成员,返回时将它的revents
成员的值置为0。
使用poll的echo服务器程序
代码如下:
1 |
|
- 声明一个
pollfd
结构数组client
,存在OPEN_MAX
个元素。client
数组的第一项用于监听套接字,并把其余各项的描述符成员置为-1。第一项设置POLLRDNORM
事件,这样当有新的连接准备好被接受时poll
将通知我们。max_index
变量表示client
数组当前正在使用的最大下标值。 - 调用
poll
以等待新的连接或者现有连接上有数据可读。当一个新的连接被接受后,在client
数组中查找第一个描述符成员为-1的可用项。注意,下标是从1开始搜索,因为client[0]
固定用于监听套接字。找到一个可用项之后,把新连接的描述符保存到其中,并设置POLLRDNORM
事件。 - 检查某个现有连接上的数据,两个返回事件是
POLLRDNORM
和POLLERR
。POLLERR
并没有在event
成员中设置,因为它在条件成立时总是返回。检查POLLERR
的原因在于:有些实现在一个连接上接收到 RST 时返回的是POLLERR
事件,而其他实现返回的只是POLLRDNORM
。无论哪种情形,我们都调用read
,当有错误发生时,read
将返回这个错误。当一个现有连接由它的客户终止时,就把它的fd成员置为-1。