2014-03-12 28 views
0

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

} 

现在,通过添加延迟(每行的进入管道的输入之后休眠)时,它解决了上述问题。这是为什么 ?无论如何要避免这种情况?下面是结果与睡眠和无壳:

[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

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

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

因此,考虑在你的文件中的几行,你可以阅读例如60个字节的fgets,然后你写150个字节到管道(意思是90个字节的垃圾也到那里)。

你结束了这个:

输入:

first line 
second line 
third line 

管数据:

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

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

+0

工作就像一个魅力,我会期待写在字符串的结尾停止。你有什么想法为什么它在睡眠中工作? –

+1

睡眠工作最有可能是垃圾是所有的空让第二个进程有足够的时间清空管道缓冲区(并且printf没有打印所有NULL字节)。至于缺少一些字节的文本,考虑20字节边界是否以NULL终止的垃圾字节开始,例如“'\ 0'mystsring”。然后printf会忽略这一点,并丢弃你的真实数据。 – Milan