8

手册页对 poll(2) 说:

POLLHUP - 挂断(仅输出)

POLLNVAL - 无效请求:fd 未打开(仅输出)

究竟有什么区别?编写一个简单的程序显示POLLNVAL如果我关闭文件描述符将触发,然后尝试从关闭的 fd 中读取。但是,我想不出一种方法来返回POLLHUP.

4

3 回答 3

16

POLLNVAL相当于EBADF:这意味着文件描述符实际上并不引用任何打开的文件,即它是closed 或从不打开。除非由于编程错误或故意尝试查询文件描述符是否无效,否则这种情况永远不会发生。外部条件,例如对等点关闭网络套接字或管道的末端,永远不会将您的文件描述符关闭到的套接字或管道的末端。如果可以的话,这将导致基本上任何使用套接字/管道/等的程序存在大量漏洞。

POLLHUP,另一方面,表示您的文件描述符是有效的,但它处于以下状态:

设备已断开连接,或者管道或 FIFO 已被打开以进行写入的最后一个进程关闭。一旦设置,FIFO 的挂起状态将持续到某个进程打开 FIFO 进行写入或直到 FIFO 的所有只读文件描述符关闭。此事件和 POLLOUT 互斥;如果发生挂断,则流永远不可写。但是,此事件和 POLLIN、POLLRDNORM、POLLRDBAND 或 POLLPRI 不是互斥的。此标志仅在 revents 位掩码中有效;在 events 成员中应忽略它。

资料来源: http: //pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html

如果你想看POLLHUP,只需打开一个pipe,关闭阅读端,然后用 查询写作端poll

于 2014-08-05T20:13:56.953 回答
5

如果您的目标是编写一个触发 的程序POLLHUP,请尝试打开管道,关闭它的写入端然后poll()ing 读取端(代码修改自http://www.greenend.org.uk/rjk/tech/投票.html):

#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int main(void)
{
    int p[2];
    struct pollfd ufd;

    if (pipe(p) < 0) {
        perror("pipe");
        return EXIT_FAILURE;
    }
    if (close(p[1]) < 0) { /* close the write fd */
        perror("close");
        return EXIT_FAILURE;
    }

    memset(&ufd, 0, sizeof ufd);
    ufd.fd = p[0]; /* poll the read fd after the write fd is closed */
    ufd.events = POLLIN;
    if (poll(&ufd, 1, 1000) < 0) {
        perror("poll");
        return EXIT_FAILURE;
    }

    switch(ufd.revents & (POLLIN|POLLHUP)) {
        case POLLIN: printf("POLLIN\n"); break;
        case POLLHUP: printf("POLLHUP\n"); break;
        case POLLIN|POLLHUP: printf("POLLIN|POLLHUP\n"); break;
        case POLLERR: printf("POLLERR\n"); break;
        default: printf("%#x\n", (unsigned)ufd.revents); break;
    }

    return EXIT_SUCCESS;
}

以上为我打印POLLHUP

于 2014-08-05T20:15:18.580 回答
1

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

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

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

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

要观察POLLHUP,请让您的程序从终端读取并关闭终端。或者,在 Linux 上,让您的程序从管道中读取并关闭写入端(例如sleep 1 | yourprogram)。

于 2014-08-05T20:26:54.980 回答