poll函数类似于select,但与select不同的是,poll不是为每个状态(可读、可写、异常)构造一个描述符集,而是构造一个pollfd结构数组。
每个数组元素指定一个描述符标号以及所关心的状态。
struct pollfd {
int fd;
short events;
short revents;
};
events可设置的值见表格。通过这些值告诉内核我们队该描述符关心的是什么。返回是,内核设置revents成员,
用以说明对于这个描述符已经发生了什么。
POLLIN 有数据可读。
POLLRDNORM 有普通数据可读。
POLLRDBAND 有优先数据可读。
POLLPRI 有紧迫数据可读。
POLLOUT 写数据不会导致阻塞。
POLLWRNORM 写普通数据不会导致阻塞。
POLLWRBAND 写优先数据不会导致阻塞。
POLLMSG SIGPOLL消息可用。
此外,revents域中还可能返回下列事件:
POLLER 指定的文件描述符发生错误。
POLLHUP 指定的文件描述符挂起事件。
POLLNVAL 指定的文件描述符非法。
最后三行是由内核在返回时设置的,即使在events字段中没有指定这三个值,如果相应条件发生(出错了),则在revents中也有返回。
当一个文件描述符挂断了(POLLHUP),就不能再写向该描述符,但是可能从文件描述符中读取到数据。
poll最后一个参数为时间,即愿意等待多久。
与select一样,不论一个文件描述符是否阻塞,都不影响poll是否阻塞。
poll的使用(伪代码)
#define SIZE 20
#define TIME_OUT 20
所关心的文件描述符为socket;
struct pollfd fds[SIZE];
fds[0].fd = socket;
fds[0].events = POLLIN;
int nfds = 1;
int timeout = TIME_OUT ;
int ret ;
while(1)
{
ret = poll(fds, nfds, timeout);
if(ret == 0)
continue;
else if(ret < 0)
exit(0);
//循环检测所有文件描述符的events发生变化
for (i = 0; i < nfds; i++)
{ //通过fd的revents域了解哪些events变化
if (fds[i].revents == 0)
continue;
if (fds[i].revents != POLLIN)
continue;
if (fds[i].fd == socket)
{ //todo}
}
}