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

时间:2022-11-10 07:29:29

I have a problem when trying to answer an exercice, that requires that a first process writes into a pipe line by line, and that a second process reads from that pipe from a buffer of only 20 bytes. It seems that some information get "lost" in the pipe and the input lacks random bits of the initial message. Here is the code related to the problem :

我在尝试回答一个练习时遇到问题,这需要第一个进程逐行写入管道,第二个进程从一个只有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;

}

Now, by adding a delay (the sleep after the input of each line into the pipe), it solves the problem. Why is that ? And is there anyway to avoid this ? Here is the result in the shell with the sleep and without :

现在,通过添加延迟(每行输入管道后的睡眠),它解决了问题。这是为什么 ?无论如何要避免这种情况吗?这是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 : I also tried reading with greater buffer size from the pipe, and everything outputs fine. I am also running on a linux distribution, if it has any importance in the behavior of pipes.

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

1 个解决方案

#1


1  

Consider what is happening when reading the input from the file, namely:

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

//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
}

So, given a few lines in your file, you may read e.g. 60 bytes with fgets, and then you write 150 bytes to the pipe (meaning 90 bytes of garbage goes there too).

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

You end up with this:

你最终得到这个:

INPUT:

INPUT:

first line
second line
third line

Pipe data:

管道数据:

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

Where the *** symbolizes the garbage data written to the pipe. Once the second process starts reading, depending on the garbage data, it may print whatever it wants.

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

#1


1  

Consider what is happening when reading the input from the file, namely:

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

//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
}

So, given a few lines in your file, you may read e.g. 60 bytes with fgets, and then you write 150 bytes to the pipe (meaning 90 bytes of garbage goes there too).

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

You end up with this:

你最终得到这个:

INPUT:

INPUT:

first line
second line
third line

Pipe data:

管道数据:

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

Where the *** symbolizes the garbage data written to the pipe. Once the second process starts reading, depending on the garbage data, it may print whatever it wants.

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