gpt4 book ai didi

c - 命名管道上的 Poll() 会不断并立即返回 POLLHUP

转载 作者:IT王子 更新时间:2023-10-29 00:51:25 28 4
gpt4 key购买 nike

打开一个命名管道(由mkfifo创建的fifo)带有非阻塞标志(打开(...O_NONBLOCK))然后开始投票(投票(...))。到目前为止,一切都很好。然后从命令行我做了几个

echo 123 > /tmp/fifo

它们都按预期从管道中读出(至少我认为它们应该正常工作)。

我的问题是,在第一个 echo 之后,设置了 POLLHUP 并且卡住了,poll 立即返回 从那个点开始。

如何清除/摆脱POLLHUP

它开始让我发疯:(

是的,管道的另一端关闭了(在之前打开之后),所以它变成了半关闭状态,但我的那一端仍然是敞开的,而且还活着,我喜欢这样。它没有死,我仍然可以通过管道接收到新的回声,它只是 poll 呼唤着 POLLHUP 的河流(我一开始甚至没有在事件中请求过,但是 poll 无论如何都可以标记它们 [man poll: "revents 可以包括事件中指定的任何事件,或值 POLLERR、POLLHUP 之一"]),因此几乎没有用。

显然我不能从集合中取出那个 fd,因为我仍然想收到关于它的新数据的通知。

我不想关闭它,因为它不是一次使用的管道,我喜欢重复使用相同的东西而不是扔掉它们......除其他外,我不再有管道名称,我只有文件描述符(从 fd 获取文件名似乎是个婊子……我也用谷歌搜索了……)

我仍然相信 Linux 的强大功能,并且必须有更好的(性能更高效/竞争条件安全)方法来做到这一点。

这是我看过的,但对解决问题没有帮助。

在绝望中,我什至尝试过做这样的事情(但没有帮助):

    int newfd = dup(fds[i].fd);
close(fds[i].fd);
dup2(newfd, fds[i].fd);
close(newfd);

有什么想法吗?我做错了什么吗?

(我总是可以回到只是尝试定期读取所有管道(这确实有效),现在这不是延迟关键,但我不知道如果它是...我会怎么做......)

这里有一些代码可以重现我的问题(这不是我要构建的生产代码,显然我想轮询的管道不止 1 个...)

#include <stdio.h>

#include <sys/types.h> // mkfifo
#include <sys/stat.h> // mkfifo

#include <unistd.h>
#include <fcntl.h>

#include <errno.h>
#include <string.h>

#include <poll.h>


int main(int argc, char **argv) {
char* pipename = "/tmp/fifo";
mkfifo(pipename, S_IWUSR | S_IRUSR | S_IRGRP);
int fd = open(pipename, O_RDONLY | O_NONBLOCK); /// O_ASYNC, O_SYNC

struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;
fds[0].revents = 0;

while (1) {
int res = poll(fds, 1, 1000);
if (res<0) { perror("poll"); return 1; }
if (res==0) { printf(".\n"); continue; }
printf("Poll [%d]: 0x%04x on %d\n", 0, fds[0].revents, fds[0].fd);

char buff[512];
int count = (int)read(fds[0].fd, buff, (size_t)(sizeof(buff)-1));
if (count>=0) {
buff[count] = 0;
printf("Pipe read %d bytes: '%s'\n", count, buff);
usleep(1000*100); /// cpu protector sleep for POLLHUP :)
}
}
return 0;
}

注意事项:

我在 Linux (lubuntu) 平台 (x64) 上使用 gcc (4.6.3)。但最后我想为嵌入式目标交叉编译它。

我敢肯定我一定是错过了一些和平的信息,所以请问...

解决方案/解决方法:

  1. mark4o 建议的解决方法 #1 是使用 O_RDWR 而不是 O_RDONLY 打开管道。这样你就不会得到恒定的 POLLHUP-s(当然你不会得到任何女巫可能是个问题)。此外,读者将需要对管道的写入权限(在某些情况下您可能没有权限)。

最佳答案

因为管道只提供一个单向 channel (而不是像套接字那样为每个客户端提供单独的双向 channel ),所以通常在只有一个进程需要将数据发送到另一个进程时使用它们。当编写者关闭管道时,POLLHUP(挂起)告诉读者管道已关闭,它可以完成处理并终止。

可以使用具有多个写入器的管道,但如果消息可能大于 PIPE_BUF 或 512 字节,则需要小心。否则,因为它只是一个单一的 channel ,来自多个同时写入的作者的消息可能会交错。同样因为它是一个单一的 channel ,你将无法判断一条长消息是来自一个客户端的单次写入还是来自多个客户端的多次写入,除非你有一些约定,比如每条客户端消息一行(以换行符终止) .

POLLHUP 表示最后一个写入者关闭了管道,并一直持续到另一个进程打开管道进行写入或被所有读者关闭。如果您不希望这样,请使用 O_RDWR 而不是 O_RDONLY 打开管道,这样管道将保持打开状态。这是可行的,因为只要您打开它,总会有一个编写器(您的程序)。

关于c - 命名管道上的 Poll() 会不断并立即返回 POLLHUP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22021253/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com