【问题标题】:C program read data from FIFOC程序从FIFO读取数据
【发布时间】:2014-05-12 06:10:35
【问题描述】:

我有两个程序来写入和读取 FIFO。一个是读取(O_RDONLY)一个 FIFO。另一个是将数据写入这个 FIFO。这是代码:

读取:可执行文件名为读取。

#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>

int main(int argc, char *argv[])
{
    int fd, nread;
    const char *pipe_file = "/tmp/test_fifo";

    char buf[0x100] ;

    fd = open(pipe_file, O_RDONLY);

    while(1) {
        printf("\n"); /*  */
        memset(buf, 0, 100);
        nread = read(fd, buf, 0x100);
        printf("data is %s", buf);
        sleep(1);
    }

    return 0;
}

Write:可执行文件名为write。

#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>

int main(int argc, char *argv[])
{
    int fd;
    int num = 1234;
    char *s = "changzhi";
    const char *pipe_file = "/tmp/test_fifo";


    fd = open(pipe_file, O_WRONLY);
    write(fd, s, strlen(s));

    return 0;
}

名为 /tmp/test_fifo 的 FIFO 已存在。当我运行 read 读取 FIFO 并运行 write 写入 FIFO 时,一切正常。 但是,当读取代码中没有printf("\n"); 时,read 无法读取数据。我不知道为什么。有人可以帮助我吗?非常感谢!

【问题讨论】:

  • 请注意,有系统提供的命令称为readwrite。你确定你没有不小心使用其中之一吗? (例如,如果你使用./read./write,你会没事的。)在你的代码中,你不检查你的打开是否成功;您没有报告您的打开成功;你不检查你的读或写操作是否成功;当写入成功时,您不会报告。您需要并行运行程序:./read &amp; ./write./write &amp; ./read

标签: c fifo


【解决方案1】:

你的第二个printf() 被缓冲,直到\n 被写入。读取没有被阻塞:-)

重写你的循环:

while(1) {
    memset(buf, 0, 100);
    nread = read(fd, buf, 0x100);
    printf("data is %s\n", buf);
    sleep(1);
}

【讨论】:

  • data is 调用printf() 中没有换行符,循环回到顶部,然后在sleep(1) 引起的1 秒延迟后执行printf("\n")。但你说得对,以这种方式做事……是不合常规的,我们可以这么说吗?
  • 你能解释一下buffer and blocked的细节吗?非常感谢!
  • 输出默认是行缓冲的; printf() 的输出在出现换行符之前不会出现,然后出现换行符之前的数据。换行符之后的任何内容都会等到换行符出现。因此,您的第二个printf() 不会强制输出数据。然而,在 1 秒睡眠后,循环回到顶部,printf("\n"); 强制退出“data is …”材料。在原始代码中,循环是无限的,直到您中断程序,因为您不测试 EOF 或读取错误。
  • 对于“阻塞”,read() 不会返回,直到 FIFO 中有一些数据要返回,或者直到没有打开 FIFO 的写入器,因此 read() 返回带有 EOF(读取 0 字节)。您的代码会忽略此返回代码,因此循环会无限期地继续。 open() 也会阻塞;在每个程序中,直到有另一个(另一个)进程也打开 FIFO 时才会完成。
【解决方案2】:

在严格的编译选项下干净地编译代码:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -Werror write.c -o write
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -Werror read.c -o read
$

代码基本上对我有用。我添加了错误检查。稍微奇怪的argv[argc-argc] 打印argv[0],但避免了关于argc 未使用的警告(由于-Werror 而导致的错误)。

read.c

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

int main(int argc, char **argv)
{
    int fd, nread;
    const char *pipe_file = "/tmp/test_fifo";

    char buf[0x100];

    if ((fd = open(pipe_file, O_RDONLY)) < 0)
    {
        fprintf(stderr, "%s: Failed to open FIFO %s\n", argv[argc-argc], pipe_file);
        return 1;
    }
    printf("%s: open successful\n", argv[0]);

    while(1) {
        printf("\n"); /*  */
        memset(buf, 0, 100);
        nread = read(fd, buf, 0x100-1);
        if (nread <= 0)
            break;
        printf("data is %s\n", buf);
        sleep(1);
    }

    return 0;
}

write.c

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

int main(int argc, char *argv[])
{
    int fd;
    char *s = "changzhi";
    const char *pipe_file = "/tmp/test_fifo";

    if ((fd = open(pipe_file, O_WRONLY)) < 0)
    {
        fprintf(stderr, "%s: failed to open FIFO %s\n", argv[argc-argc], pipe_file);
        return 1;
    }
    printf("%s: open successful\n", argv[0]);
    if (write(fd, s, strlen(s)) <= 0)
    {
        fprintf(stderr, "%s: failed to open FIFO %s\n", argv[argc-argc], pipe_file);
        return 1;
    }
    printf("%s: write successful\n", argv[0]);

    return 0;
}

样本输出

$ ./read & ./write
[1] 85542
./write: open successful
./write: write successful
./read: open successful

data is changzhi
$ 

[1]+  Done                    ./read
$ ./write & ./read
[1] 85544
./write: open successful
./read: open successful

./write: write successful
data is changzhi

[1]+  Done                    ./write
$

如果 FIFO 不存在,程序会明智地报告错误。

【讨论】:

  • 感谢您的回答。但是我仍然对代码有一些问题。当我在阅读程序中评论printf("\n"); 时,它无法工作。缓冲区是否有问题导致读取操作被阻止?你可以看到@cadrian 的回答。
  • 当我从read.c 中删除printf("\n"); 行时,程序运行良好——它只是少打印了一个换行符(这可以说是一种改进)。您是否逐字复制了代码,或者您是否尝试将我的更改修改到您的代码中?你在哪个平台上工作?我正在使用 GCC 4.9.0 在 Mac OS X 10.9.2 Mavericks 上进行测试,尽管我希望代码可以在当前千年的任何 POSIX-ish 平台上使用任何 C 编译器正常工作(尽管你需要调整非 GCC 编译器的编译标志,当然,或者真正旧版本的 GCC)。
  • 我在 CentOS 6.4 上测试,gcc 版本是 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC)。
  • 嗯,我当然不希望 CentOS 6.4 和 GCC 4.4.7 有任何问题。您是否逐字复制了我的答案中的代码?您是否使用我显示的选项进行编译?我检查了使用 GCC 4.8.2 在 Ubuntu 14.04 上编译的结果,无论有无 printf("\n"); 行,它都表现良好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-10
相关资源
最近更新 更多