如何处理Linux套接字revellent POLLERR,POLLHUP和POLLNVAL?

我想知道当轮询设置这些位时应该做什么? closures套接字,忽略它或什么?

POLLHUP表示插座不再连接。 在TCP中,这意味着FIN已经收到并发送。

POLLERR表示套接字出现异步错误。 在TCP中,这通常意味着RST已被接收或发送。 如果文件描述符不是套接字, POLLERR可能意味着设备不支持轮询。

对于上述两种情况,套接字文件描述符仍处于打开状态,尚未关闭(但shutdown()可能已经被调用)。 文件描述符上的close()将释放仍然代表套接字保留的资源。 理论上,应该可以立即重用套接字(例如,用另一个connect()调用)。

POLLNVAL表示套接字文件描述符未打开。 close()它将是一个错误。

这取决于确切的错误性质。 使用getsockopt()来查看问题:

 int error = 0; socklen_t errlen = sizeof(error); getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen); 

价值观: http : //www.xinotes.net/notes/note/1793/

最简单的方法是假定套接字在任何情况下都不再可用并关闭它。

POLLNVAL表示文件描述符的值是无效的。 它通常表示程序中有错误,但是如果您关闭了文件描述符,并且从那以后可能重用了描述符,则您可以依赖poll返回POLLNVAL

POLLERR类似于来自select错误事件。 它表示readwrite调用会返回错误状态(例如I / O错误)。 这不包括通过其errorfds掩码select信号但是通过POLLPRI poll信号的带外数据。

POLLHUP基本上意味着连接的另一端已经关闭了连接的结束。 POSIX将其描述为

该设备已断开连接。 这个事件和POLLOUT是互斥的。 如果发生挂断,则流永远不可写入。

对于一个终端来说,这足够清楚了:终端已经消失(产生SIGHUP的相同事件:调制解调器会话已终止,终端仿真器窗口已关闭等)。 POLLHUP永远不会被发送到一个普通的文件。 对于管道和插座, 取决于操作系统 。 Linux在管道写入结束的程序关闭管道时设置POLLIN|POLLHUP ,并在套接字的另一端关闭套接字时设置POLLIN|POLLHUP ,而仅在套接字关闭时才POLLIN 。 最近* BSD在管道的写入结束时关闭管道,设置POLLIN|POLLUP ,并且套接字的行为更加可变。

最小的FIFO示例

一旦你了解了这些情况发生的时候,应该很容易知道该怎么办。

 #define _XOPEN_SOURCE 700 #include <fcntl.h> /* creat, O_CREAT */ #include <poll.h> /* poll */ #include <stdio.h> /* printf, puts, snprintf */ #include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */ #include <unistd.h> /* read */ int main(void) { char buf[1024]; int fd, n; short revents; struct pollfd pfd; fd = open("poll0.tmp", O_RDONLY | O_NONBLOCK); pfd.fd = fd; pfd.events = POLLIN; while (1) { puts("loop"); poll(&pfd, 1, -1); revents = pfd.revents; if (revents & POLLIN) { n = read(pfd.fd, buf, sizeof(buf)); printf("POLLIN n=%d buf=%.*s\n", n, n, buf); } if (revents & POLLHUP) { printf("POLLHUP\n"); close(pfd.fd); pfd.fd *= -1; } if (revents & POLLNVAL) { printf("POLLNVAL\n"); } if (revents & POLLERR) { printf("POLLERR\n"); } } } 

编译:

 gcc -o poll.out -std=c99 poll.c 

用法:

 sudo mknod -m 666 poll0.tmp p ./poll.out 

在另一个外壳上:

 printf a >poll0.tmp 

POLLHUP

如果您不修改源代码: ./poll.out输出:

 loop POLLIN n=1 buf=a loop POLLHUP loop 

所以:

  • 输入变得可用时发生POLLIN
  • 当文件被printf关闭时发生POLLHUP
  • close(pfd.fd);pfd.fd *= -1; 干净的事情,我们停止接受POLLHUP
  • poll永远挂起

这是正常的操作。

您现在可以编辑FIFO以等待下一个open ,或者如果完成,则退出循环。

POLLNAL

如果你注释掉pfd.fd *= -1;./poll.out打印:

 POLLIN n=1 buf=a loop POLLHUP loop POLLNVAL loop POLLNVAL ... 

并永远循环。

所以:

  • POLLINPOLLHUPclose一样像以前一样发生
  • 由于我们没有将pfd.fd设置为负数,所以poll不断尝试使用我们关闭的fd
  • 这永远返回POLLNVAL

所以我们看到,这不应该发生,并指出您的代码中的错误。

POLLERR

我不知道如何用FIFO生成POLLERR 。 让我知道如果有办法。 但是应该可以使用设备驱动程序的file_operations

在Ubuntu 14.04测试。