POLLHUP与POLLNVAL,或什么是POLLHUP?

时间:2014-08-05 19:53:56

标签: c unix pipe poll-syscall

该联机帮助页用于民意调查(2):

  

POLLHUP - 挂断(仅输出)

     

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

究竟有什么区别?编写一个简单的程序表明,如果我关闭文件描述符,POLLNVAL将触发,然后尝试从关闭的fd读取。但是,我无法找到返回POLLHUP的方法。

3 个答案:

答案 0 :(得分:9)

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

另一方面,

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

  

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

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

如果您想查看POLLHUP,只需打开pipe,关闭阅读结束,然后使用poll查询结尾。

答案 1 :(得分:2)

如果您的目标是编写一个触发POLLHUP的程序,请尝试打开管道,关闭它的写入结束然后poll()读取结束(代码从{{3修改) }}):

#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

答案 2 :(得分:1)

POLLNVAL表示文件描述符值无效。它通常表示您的计划中存在错误,但如果您关闭了文件描述符并且从那时起您没有打开任何文件,那么您可以依赖poll返回POLLNVAL重用了描述符。

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

  

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

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

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