c - 非阻塞并行 FIFO

标签 c linux

我对两个程序的交互有疑问:

程序 I 必须定期检查是否有来自程序 II 的数据。这应该是非阻塞的。

程序 II 可以在多个实例中运行,因此是并行的。它向程序 I 发送一些数据,然后退出。数据的确切顺序并不那么重要,如果在另一组数据之后 1 秒发送的数据也在 ~1 秒后接收到就足够了。

我的第一个方法是使用 FIFO: “服务器”

int main()
{
int fd;
unlink("/tmp/ctl_fifo");
if (mkfifo("/tmp/ctl_fifo", 0666) == -1)
{
    printf("Error creating FIFO\n");
}

while (true)
{
    if ((fd = open("/tmp/ctl_fifo", O_RDONLY | O_NONBLOCK)) < 0)
    {
        printf("Error opening FIFO\n");
    }
    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 2000;
    fd_set set;
    FD_ZERO(&set);
    FD_SET(fd, &set);
    select(fd + 1, &set, NULL, NULL, &timeout);
    if (FD_ISSET(fd, &set))
    {
        char buf[20];
        int r = read(fd,buf, sizeof(buf)); 
        printf("%s\n", buf);
    }
    sleep(1);
}
return 0;
}

“客户”

int main()
{
while (true)
{
int fd;
fd = open("/tmp/ctl_fifo", O_WRONLY);
if (fd < 0)
{
    printf("Error opening fifo\n");
}
char buf[] = "Blablubb";
write(fd, buf, sizeof(buf));
sleep(0.1);
}
return 0;
}

问题在于数据可能会被打乱。输出看起来像这样:

Blablubb
ablubb
ubb
b
Blablubb
...

我的问题是:我做错了什么?有没有办法确保数据不会被扰乱?还是有一种完全不同的方法来处理这个问题?

最佳答案

首先,你的资源泄露严重;每次你的循环运行时,你都打开一个新的流,在那个循环迭代结束时,流泄漏,漂浮在稀薄的空气中,就好像它从未存在过一样......问题是它确实存在存在,而您没有关闭


其次,当您使用 O_NONBLOCK 打开流时,您不需要使用 select


read 将在没有任何内容可读时立即返回(错误值),并且使用 O_NONBLOCK 打开流。

int r = read(fd,buf, sizeof(buf)); 
printf("%s\n", buf);

read 返回一个 ssize_t(与 size_t 等效的签名)。所以 int r 应该是 ssize_t r


继续(从上一段)到 printf...

printf("%s\n", buf); // THIS IS WRONG!

首先,您需要检查 r。完全有可能没有收到任何字节,buf 包含纯粹的垃圾。也有可能合并两个写入(并且您最终只打印其中一个)。

为简单起见,我建议您一次接收(并打印)一个字节,接收'\0' 时除外;打印 '\n' 而不是 '\0'。像这样:

int fd = open("/tmp/ctl_fifo", O_RDONLY | O_NONBLOCK);
if (fd < 0)
{
    printf("Error opening FIFO\n");
}

for (;;)
{
    unsigned char c;
    ssize_t r = read(fd, &c, 1);
    if (r < 0 && errno == EAGAIN) {
        /* read sets EAGAIN when no data is available on otherwise valid
         * non-blocking streams, and returns -1... so we continue looping
         * when that happens */
        continue;
    }
    if (r <= 0) {
        /* Any value less than zero without errno == EAGAIN should terminate
         * ... and r == 0 means EOF */
        break;
    }
    putchar(c == '\0' ? '\n' : c);
}

close(fd);

关于c - 非阻塞并行 FIFO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31183404/

相关文章:

linux - 在树莓派 3 中使用 shell 编程禁用后启用 HDMI 端口

python - 接收 linux 信号并与线程交互

linux - grep --include =""比文件名花费的时间长很多

c - 根据 C 标准的严格解释,允许对可能无效的指针进行操作

c - 尝试分配不兼容的类型时出错

c - 调试内存泄漏

linux - 松鼠邮件数据副本

c - Pipe Reader 看不到 EOF 或 EOS

c - 使用strtol过滤不良命令提示符并打印错误消息(C)

linux - 如何在不执行 pull 的情况下查看最后的远程提交评论