使用管道向子进程发送多个字符串

时间:2012-05-26 14:54:51

标签: c linux fork pipe

我在Linux中有一个任务,但我无法使用它。

我有一个程序接收文本文件作为参数。然后,它使用fork()创建子进程,并逐行将作为参数接收的文本文件的内容发送到子进程。子进程需要对行进行计数并返回父进程接收的行数。

这是我迄今为止所拥有的,但有些子进程没有收到所有的行。对于我的测试,我使用了一个包含9行的文本文件。父母将9行作为字符串发送,但子进程只收到2或3行。

我做错了什么?

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

int main(int argc, char *argv[])
{  
  char string[80];
  char readbuffer[80];
  int pid, p[2];
  FILE *fp;
  int i=0;
  if(argc != 2)
  {
    printf("Syntax: %s [file_name]\n", argv[0]);
    return 0;    
  }
  fp = fopen(argv[1], "r");
  if(!fp) 
  {    
    printf("Error: File '%s' does not exist.\n", argv[1]);
    return 0;
  }
  if(pipe(p) == -1)
  {
    printf("Error: Creating pipe failed.\n");
    exit(0);
  } 
  // creates the child process
  if((pid=fork()) == -1)
  {
   printf("Error: Child process could not be created.\n");
    exit(0);
  }  

  /* Main process */
  if (pid) 
  { 
    // close the read
    close(p[0]);    
    while(fgets(string,sizeof(string),fp) != NULL)
    {                
       write(p[1], string, (strlen(string)+1));
       printf("%s\n",string);
    } 

    // close the write
    close(p[1]);
    wait(0);
  }

  // child process
  else 
  {   
    // close the write
    close(p[1]); 

    while(read(p[0],readbuffer, sizeof(readbuffer)) != 0) 
    {
      printf("Received string: %s\n", readbuffer);    
    }

    // close the read
    close(p[0]); 
  } 
  fclose(fp);       
}

5 个答案:

答案 0 :(得分:3)

您正在将null终止符发送到另一个进程:

   write(p[1], string, (strlen(string)+1));

这会让结果变得混乱,因为当您打印收到的内容时,您只能看到空终结符。

如果你这样做:

   write(p[1], string, strlen(string));

你应该得到你所期望的。

答案 1 :(得分:3)

管道是单向进程间通信通道。您必须创建2个管道,一个用于与子进程通信,另一个用于读取数据。

请记住在两个进程中关闭管道的未使用侧。

答案 2 :(得分:1)

您没有计算行数,而是计算read(2)返回的次数。

使用管道时,read(2)会从管道中提取尽可能多的数据:min(pipe_available, space_available)。它不关心换行符,0字节等。使它工作的简单技巧:

  • 使用循环来readbuffer并寻找\n
  • 使用fdopen + fgets(我觉得这可能存在缺陷)

答案 3 :(得分:1)

查看管道(man 2管道)的联机帮助页,您尝试编写的程序就是一个例子,与您的程序进行比较:)

答案 4 :(得分:0)

感谢您的建议。这就是我现在所拥有的,它的工作原理,但如何将答案发回给父母?因为父进程需要答案。

if (pid) /* Main process */
  { 
    /* Close the read */
    close(p[0]);    
    while(fgets(string,sizeof(string),fp) != NULL)
    {   
    write(p[1], string, (strlen(string)));    
    }    
    /* Close the write */
    close(p[1]);
    wait(0);
    printf("\nMain process with PID=%d has terminated succesfully.\n", getpid());
   }
   else /* Child process */
   {   
     /* Close the write */
     close(p[1]);    
     while( read(p[0], readbuffer, sizeof(readbuffer)) > 0) 
     {
       int j=0;
       for(j; j<sizeof(readbuffer); j++)
       {    
       if (readbuffer[j] == '\n')
       { 
          i++;    
       }
        }  
      }
      /* Close the read */
      close(p[0]); 
      printf("\nChild process with PID=%d has terminated succesfully.\nChild process received %d lines from the parent process.\n",getpid(), i);
    }