重复将管道读入小缓冲区的问题

时间:2014-03-12 10:52:30

标签: c linux unix pipe

我在尝试回答一个练习时遇到问题,这需要第一个进程逐行写入管道,第二个进程从一个只有20个字节的缓冲区中读取该管道。似乎有些信息会丢失"在管道中,输入缺少初始消息的随机位。以下是与问题相关的代码:

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

#define BUFF_SIZE 20
#define LINE_SIZE 150


int main(){

    pid_t idp1, idp2;
    int pipefd[2];
    if (pipe(pipefd) == -1) return 3; //Pipe error


    if ((idp1 = fork()) == 0){

        //SON 1
        close(pipefd[0]);
        FILE* input = fopen("input.txt", "r");
        char line[LINE_SIZE];

        //Get a line
        while(fgets(line, LINE_SIZE, input)){ 


            //Sends the line
            write(pipefd[1], line, LINE_SIZE);
            sleep(1);
        }
        fclose(input);
        close(pipefd[1]);

    }else if(idp1 != -1){

        if ((idp2 = fork()) == 0){

            //SON 2
            close(pipefd[1]);
            char inMsg[BUFF_SIZE] = "";
            int received;

            while(received = read(pipefd[0], inMsg, BUFF_SIZE)){
                inMsg[received] = '\0';
                printf("%.*s", received, inMsg);
            }

        }else if(idp2 != -1){

            //Father
            close(pipefd[0]);
            close(pipefd[1]);
            //SleepOrWhatever();

        }else return 2; //Fork 2 error

    }else return 1; //Fork 1 error

    return 0;

}

现在,通过添加延迟(每行输入管道后的睡眠),它解决了问题。这是为什么 ?无论如何要避免这种情况吗?这是shell中带睡眠但没有的结果:

[010][input.txt]
[049][[Fichier d'entrée du programme TD0 forkpipe.c].]
[001][]
[054][[003]Il contient des lignes [de longueurs variables].]
[041][avec des lignes blanches (longuer [000])]
[001][]
[009][d'autres]
[020][         commencant]
[036][                    par des blancs.]
[010][et enfin,]
[021][une dernière ligne.]


[010][input.txt]
hier d'entrée du programme TD0 forkpipe.c].]
[001][]
]Il contient des lignes [de longueurs variables].]
[041][avec des lignes blanches (longuer [000])]
[009][d'autres]
     commencant]
[036][                    par des blancs.]
nfin,]
[021][une dernière ligne.]

PS:我也试过从管道中读取更大的缓冲区大小,一切都输出正常。如果它对管道的行为有任何重要性,我也在linux发行版上运行。

1 个答案:

答案 0 :(得分:1)

考虑从文件中读取输入时发生的事情,即:

//Get a line
while(fgets(line, LINE_SIZE, input)){ <<-- fgets reads a line _up_ to a LINE_SIZE bytes (and the result will be null terminated)


    //Sends the line
    write(pipefd[1], line, LINE_SIZE); <<-- Write LINE_SIZE bytes to the pipe
}

因此,如果您的文件中有几行,您可以阅读,例如使用fgets创建60个字节,然后向管道写入150个字节(这意味着90个字节的垃圾也会出现在那里)。

你最终得到了这个:

INPUT:

first line
second line
third line

管道数据:

first line***second line*** third line ***

***表示写入管道的垃圾数据。一旦第二个进程开始读取,根据垃圾数据,它可以打印任何想要的内容。