【问题标题】:Sending multiple strings using pipes to child process使用管道向子进程发送多个字符串
【发布时间】:2012-05-26 14:54:50
【问题描述】:

我在 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);       
}

【问题讨论】:

  • 这是作业吗?如果是这样,请添加适当的标签。无论如何,这里有一个提示:如果数据流中有'\0'read 不会停止读取。
  • 子进程收到“2 或 3 行”还是其 read() 返回“2 或 3 ”?这些是不同的场景。我敢打赌是后者。

标签: c linux fork pipe


【解决方案1】:

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

记得关闭两个进程中未使用的管道。

【讨论】:

    【解决方案2】:

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

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

    这会使结果令人困惑,因为当您打印收到的内容时,您最多只能看到空终止符。

    如果您改为这样做:

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

    你应该得到你所期望的。

    【讨论】:

      【解决方案3】:

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

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

      • 使用循环遍历readbuffer 并寻找\n
      • 使用fdopen + fgets(我感觉这可能有缺陷)

      【讨论】:

      • 他编写的代码不会将'\n' 发送到子进程。他必须寻找'\0'
      • @celtschk fgets 不会留下\n 吗?我认为它确实在换行符(保留)或文件结束后之后不会读取其他字符。 - 7.21.7.2
      • 哎呀,你是对的。我不知道fgets 在这方面与gets 不同(谁发明了 那个 界面!?)
      • @celtschk 我什至不知道gets 没有包含换行符!哈,不错找到了!
      【解决方案4】:

      查看管道的手册页( man 2 pipe ),您正在尝试编写的程序作为示例,与您的比较:)

      【讨论】:

        【解决方案5】:

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

        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);
            } 
        

        【讨论】:

          猜你喜欢
          • 2020-06-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-02
          • 2021-06-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多