流程之间的通信-管道和FIFO

时间:2018-12-20 14:45:06

标签: c linux pipe fifo mkfifo

我需要创建具有3个进程的程序:

  1. 第一个进程应重复读取/dev/urandom,并通过管道每个周期向第二个进程发送15个字符。
  2. 第二个进程应将接收到的数据转换为十六进制,然后通过 fifo 将结果发送到第三个进程。
  3. 第三步应该打印接收到的数据。

这是我到目前为止写的。使用管道的通信可以正常工作,但是fifo存在一些问题-当我将n更改为较大的数字(例如100000或1000000)时,程序无法启动。当它较小时(例如500或1000),该程序将起作用。这可能是什么原因?

这是我的运行方式:

cat /dev/urandom | ./a.out

这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#define FIFO "my_fifo"

int main(void) {
    int pdesk[2];
    char buf[15];
    char buffer[15];
    char hex[30];
    char f[30];
    int len;
    int n;

    n = 100;

    umask(0);
    mkfifo(FIFO, 0666);

    pipe(pdesk);

    if (fork() == 0) {
        for (int i = 0; i < n; i++) {
            read(STDIN_FILENO, buffer, 15);
            write(pdesk[1], buffer, 15);
        }
        close(pdesk[1]);
    } else {
        sleep(1);
        int fp;

        for(int i = 0; i < n; i++) { 
            read(pdesk[0], buf, 15);

            for(int a = 0, b = 0; b < 30; ++a, b+= 2) 
                sprintf(hex + b, "%02x", buf[a] & 0xff);

            fp = open(FIFO, O_WRONLY);
            write(fp, hex, 30);
            close(fp);
            usleep(10000);
        }
        close(pdesk[0]);
    }

    if (fork() == 0) {
        sleep(2);
        int fp;

        for (int i = 0; i < n; i++) {
            fp = open(FIFO, O_RDONLY);
            read(fp, f, 30);
            printf("Odczytano: %s\n", f);
            close(fp);
            usleep(10000);
        }
    }    
}

2 个答案:

答案 0 :(得分:1)

如果我理解您的代码正确,它将执行以下操作:

使用第一个fork,您将启动一个从stdin读取并写入管道的子项。

您的父进程从管道读取并写入FIFO。

父进程完成循环后,它将调用第二个fork以创建另一个子进程,该子进程将从FIFO中读取并打印数据。

当循环计数太大时,您将达到FIFO的缓冲区限制,而父级将阻塞,因为没有进程从FIFO中读取。当该进程无法写入FIFO时,它将永远不会创建预期从FIFO读取的子进程。

我认为主要的问题是,您应该在开始从管道读取数据并将其写入FIFO的循环之前创建第二个子代。

一些补充说明:

使用cat /dev/urandom | ./a.out时,程序不会直接读取/dev/urandom。它从行为可能不同的管道读取数据。

您应始终检查read的返回值。它会告诉您已读取的字节数可能少于您要求的字节数。如果要精确地包含15个字符,则少于15个字符可能需要阅读几次。 write也是如此。

答案 1 :(得分:0)

非常感谢。当显示数据的进程位于其他子进程之上时,它最终将工作。

  

使用cat / dev / urandom | ./a.out您的程序不会直接读取/ dev / urandom。它从行为可能不同的管道读取。

我该如何更改?

程序还需要以与/ dev / urandom相同的方式读取文件,例如:

cat file.txt | ./a.out

我听取了您的建议,开始检查read的值,现在它没有超出文件范围。问题是我不知道如何检查调用了哪个参数(因此我无法检查文件的长度)-如果是file.txt,/ dev / urandom,没有其他任何东西。我尝试过

int main(char argc, char* argv[])

但是argv始终是./a.out,无论我叫什么。有什么办法可以检查吗?