21

我想知道当 poll 设置这些位时应该做什么?关闭套接字,忽略它还是什么?

4

4 回答 4

25

APOLLHUP表示套接字不再连接。在 TCP 中,这意味着 FIN 已被接收和发送。

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

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

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

于 2014-07-16T22:23:13.843 回答
11

这取决于确切的错误性质。使用 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/

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

于 2014-07-16T22:17:19.877 回答
5

POLLNVAL表示文件描述符值无效。它通常表示您的程序中存在错误,但如果您关闭了文件描述符并且此后没有打开任何可能重用描述符的文件,您可以依赖poll返回。POLLNVAL

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

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

设备已断开连接。此事件和 POLLOUT 互斥;如果发生挂断,则流永远不可写。

这对于终端来说已经足够清楚了:终端已经消失(生成 SIGHUP 的同一事件:调​​制解调器会话已终止,终端仿真器窗口已关闭等)。POLLHUP永远不会为常规文件发送。对于管道和套接字,它取决于操作系统。Linux设置POLLHUP管道写入端的程序何时关闭管道,并设置POLLIN|POLLHUP套接字的另一端何时关闭套接字,但POLLIN仅用于套接字关闭。POLLIN|POLLUP当管道的写入端关闭管道时,最近的 *BSD 设置,并且套接字的行为更加多变。

于 2014-08-11T18:26:26.513 回答
2

最小 FIFO 示例

一旦您了解了这些情况何时发生,就应该很容易知道如何处理它们。

民意调查.c

#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");
        }
    }
}

GitHub 上游.

编译:

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

用法:

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

在另一个外壳上:

printf a >poll0.tmp

民意调查

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

loop
POLLIN n=1 buf=a
loop
POLLHUP
loop

所以:

  • POLLIN当输入可用时发生
  • POLLHUP当文件被关闭时发生printf
  • close(pfd.fd);把东西pfd.fd *= -1;清理干净,我们就停止接收了POLLHUP
  • poll永远挂起

这是正常操作。

您现在可以重新启动 FIFO 以等待下一个open,或者在完成后退出循环。

轮询

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

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

并永远循环。

所以:

  • POLLIN并且像以前一样POLLHUP发生close
  • 因为我们没有设置pfd.fd为负数,poll所以一直尝试使用fd我们关闭的
  • 这将POLLNVAL永远返回

所以我们看到这不应该发生,并表明您的代码中存在错误。

轮询器

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

在 Ubuntu 14.04 中测试。

于 2017-05-24T05:31:01.850 回答