如何在 Linux 中使用 poll C 函数监视命名管道?

发布于 2024-11-04 12:58:07 字数 276 浏览 1 评论 0原文

我正在尝试编写一个程序,在其中我应该观察一些命名管道的末端 使用轮询功能。 我有一个 for 循环来检查每个管道,每当 poll 返回 > 0 时,我知道当管道从另一端的过程关闭时,我将得到 POLLHUP 或 POLLIN | POLLHUP 在 pollfd 结构的 revents 字段中。

我的问题是:当一个管道确实关闭并向我返回 POLLHUP 时,下一个循环会发生什么?它是否会在下一个循环和任何后续循环中一次又一次地返回 POLLHUP,或者 poll 函数是否会在第一个 POLLHUP 之后忽略它?

I am trying to write a program where i am supposed to watch the ends of some named pipes
using poll function.
I have a for loop to check every pipe whenever poll returns >0 and i know that when a pipe gets closed from the procedure at the other end, i will get POLLHUP or POLLIN | POLLHUP in the revents field of the pollfd struct.

My question is: when one pipe does indeed get closed and returns POLLHUP to me, what will happen on the next loop? Is it going to return POLLHUP again and again in the next and any subsequent loop or is poll function going to ignore it after the first POLLHUP?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

友欢 2024-11-11 12:58:08

最小示例

来源如下。用法:

sudo mknod poll0.tmp p
sudo mknod poll1.tmp p
sudo chmod 666 poll*.tmp
./poll.out

在另一个 shell 上:

printf a > poll0.tmp
printf b > poll1.tmp

输出:

loop
POLLIN i=0 n=1 buf=a
loop
POLLHUP i=0
loop
POLLIN i=1 n=1 buf=b
POLLHUP i=1
loop

请注意 poll 如何等待读取而不循环。

更酷的示例:

(while true; do date; sleep 1; done) > poll0.tmp &
(while true; do date; sleep 2; done) > poll1.tmp &

0 每隔一秒写入一次,1 每两秒写入一次,这显示了 poll() 如何同时处理两个输入,而不互相拖延。

来源:

poll.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) {
    enum { N = 2 };
    char buf[1024], path[1024];
    int fd, i, n;
    short revents;
    struct pollfd pfds[N];

    for (i = 0; i < N; ++i) {
        snprintf(path, sizeof(path), "poll%d.tmp", i);
        /* O_NONBLOCK is required or else the open blocks
         * until the other side of the pipe opens. */
        fd = open(path, O_RDONLY | O_NONBLOCK);
        if (fd == -1) {
            perror("open");
            exit(EXIT_FAILURE);
        }
        pfds[i].fd = fd;
        /* Only events in this mask will be listened to.
         * However, there are also some events that are unmaskable,
         * notably POLLHUP when pipe closes! */
        pfds[i].events = POLLIN;
    }
    while (1) {
        puts("loop");
        i = poll(pfds, N, -1);
        if (i == -1) {
            perror("poll");
            exit(EXIT_FAILURE);
        }
        for (i = 0; i < N; ++i) {
            revents = pfds[i].revents;
            if (revents & POLLIN) {
                n = read(pfds[i].fd, buf, sizeof(buf));
                printf("POLLIN i=%d n=%d buf=%.*s\n", i, n, n, buf);
            }
            if (revents & POLLHUP) {
                printf("POLLHUP i=%d\n", i);

                /* This happens when the other side closed.
                 * This event is only cleared when we close the reader. */

                /* poll won't set POLLHUP anymore once all fds are closed.
                 * Any futher polls on this will give the POLLNVAL event instead. */
                close(pfds[i].fd);

                /* negative fds are ignored. So if we negate an FD,
                 * we can both turn if off for a while, and turn it on
                 * later on by re-nagating it. */
                pfds[i].fd *= -1;
            }
        }
    }
}

编译:

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

在 Ubuntu 14.04 中测试。

GitHub 上游

回答原来的问题:

当一个管道确实关闭并向我返回 POLLHUP 时,下一个循环会发生什么?它是否会在下一个和任何后续循环中一次又一次地返回 POLLHUP,或者 poll 函数是否会在第一个 POLLHUP 之后忽略它?

删除这些行:

close(pfds[i].fd);
pfds[i].fd *= -1;

您将看到它在 POLLHUP 上永远循环。

删除只是:

close(pfds[i].fd);

你会得到 POLLNVAL 相反,因为它尝试使用封闭的 fd: 如何处理Linux套接字revents POLLERR、POLLHUP和POLLNVAL?

Minimal example

Source below. Usage:

sudo mknod poll0.tmp p
sudo mknod poll1.tmp p
sudo chmod 666 poll*.tmp
./poll.out

On another shell:

printf a > poll0.tmp
printf b > poll1.tmp

Output:

loop
POLLIN i=0 n=1 buf=a
loop
POLLHUP i=0
loop
POLLIN i=1 n=1 buf=b
POLLHUP i=1
loop

So notice how poll waits for the reads without looping.

Cooler example:

(while true; do date; sleep 1; done) > poll0.tmp &
(while true; do date; sleep 2; done) > poll1.tmp &

0 gets written every one second, and 1 every two seconds, which shows how poll() is dealing with both inputs concurrently, without stalling each other.

Source:

poll.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) {
    enum { N = 2 };
    char buf[1024], path[1024];
    int fd, i, n;
    short revents;
    struct pollfd pfds[N];

    for (i = 0; i < N; ++i) {
        snprintf(path, sizeof(path), "poll%d.tmp", i);
        /* O_NONBLOCK is required or else the open blocks
         * until the other side of the pipe opens. */
        fd = open(path, O_RDONLY | O_NONBLOCK);
        if (fd == -1) {
            perror("open");
            exit(EXIT_FAILURE);
        }
        pfds[i].fd = fd;
        /* Only events in this mask will be listened to.
         * However, there are also some events that are unmaskable,
         * notably POLLHUP when pipe closes! */
        pfds[i].events = POLLIN;
    }
    while (1) {
        puts("loop");
        i = poll(pfds, N, -1);
        if (i == -1) {
            perror("poll");
            exit(EXIT_FAILURE);
        }
        for (i = 0; i < N; ++i) {
            revents = pfds[i].revents;
            if (revents & POLLIN) {
                n = read(pfds[i].fd, buf, sizeof(buf));
                printf("POLLIN i=%d n=%d buf=%.*s\n", i, n, n, buf);
            }
            if (revents & POLLHUP) {
                printf("POLLHUP i=%d\n", i);

                /* This happens when the other side closed.
                 * This event is only cleared when we close the reader. */

                /* poll won't set POLLHUP anymore once all fds are closed.
                 * Any futher polls on this will give the POLLNVAL event instead. */
                close(pfds[i].fd);

                /* negative fds are ignored. So if we negate an FD,
                 * we can both turn if off for a while, and turn it on
                 * later on by re-nagating it. */
                pfds[i].fd *= -1;
            }
        }
    }
}

Compile with:

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

Tested in Ubuntu 14.04.

GitHub upstream.

To answer the original question:

when one pipe does indeed get closed and returns POLLHUP to me, what will happen on the next loop? Is it going to return POLLHUP again and again in the next and any subsequent loop or is poll function going to ignore it after the first POLLHUP?

Remove the lines:

close(pfds[i].fd);
pfds[i].fd *= -1;

and you will see that it loops forever over POLLHUP.

Remove just:

close(pfds[i].fd);

and you get POLLNVAL instead, as it tries to use a closed fd: How to handle the Linux socket revents POLLERR, POLLHUP and POLLNVAL?

暗恋未遂 2024-11-11 12:58:08

它将继续在 revents 中设置 POLLHUP。
另请参阅 http://linux.die.net/man/3/poll参考。

It will continue to set POLLHUP in revents.
Also, see http://linux.die.net/man/3/poll for reference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文