如何使用涉及多个读写的管道实现子进程和父进程之间的双向通信

时间:2012-04-04 04:26:09

标签: c linux pipe

我实现了一个涉及子进程和父进程之间双向通信的场景。子进程使用execvp启动另一个c程序(比如XYZ)。 Parent在pipe1的一端写入数据,pipe1的另一端复制到child的stdin。所以孩子读取这些数据,执行一些操作并将数据写回stdout。这个stdout被复制以写入pipe2的结尾,现在父读取来自pipe2的读取端。不修改外部程序XYZ。要遵循的顺序是

1)parent将数据写入pipe1 2)子进程从pipe1的重复结束(stdin)读取数据 3)child对数据进行一些修改并将数据写回stdout,stdout被复制到读取pipe2的末尾 4)父尝试从pipe2的读取端读取数据。

上述情况可以重复多次。

以上场景的示例以及示例 1)父母写1 2)子读取1并进行修改并将1(修改后)写入stdout 3)现在父母读取这些数据并打印回来 4)打印后,父对象2写入stdin 5)继续如上.....

我面临的问题是父母无法从pipe2的读取端读取数据。它实际上是在闲逛。

Imp注意:我还没有关闭pipe1的写句柄,因为我需要再次写入数据。如果我关闭手柄,我无法重新打开它,因为管道不支持它。

代码如下所示

void Child_write  (pid_t Handle);
void Parent_write (pid_t Handle, char c);
void Child_read  (pid_t Handle);
void Parent_read (pid_t Handle);

void main()
{

  pid_t Pid;
  int   writepipe[2],readpipe [2];  

  pipe(readpipe);               /* Create two file descriptors  */
  pipe(writepipe);              /* Create two file descriptors  */

  Pid = fork();

  if (Pid == 0)         
  {
     close(writepipe[1]);               /* closing writepipe's write end */
     dup2(writepipe[0],0); close(writepipe[0]);     /* duplicating writepipe's read    end to stdin*/
     close(readpipe[0]);                /* closing readpipe's read end*/
     dup2(readpipe[1],1);  close(readpipe[1]);      /* duplicating readpipe's write end to stdout*/    
     Child_read(writepipe[0]);              /* reading data from write pipe read end and then duplicating*/

  }
  else                  
  {
     close(writepipe[0]);               /* closing writepipe's read end */
     Parent_write(writepipe[1],'1');            /* pupming data to the writepipe */
     close(readpipe[1]);                /* closing the readpipes write end */
     Parent_read(readpipe[0]);              /* reading the data which is pumped into readpipe */
     //Parent_write(writepipe[1],'2');          /* pupming data to the writepipe */
     //Parent_read(readpipe[0]);

     //Parent_write(writepipe[1],'3');
     //Parent_read(readpipe[0]);
     puts("***** End of parent process*****");
  }
}

void Child_read(pid_t handle)
{
   static char* command = "./stdoutput";
   execvp(command, NULL);
}

void Parent_write(pid_t handle, char c)
{
   char Buff[] = {'\n','\n'};
   Buff[0] = c;
   int n_written= write(handle, Buff, strlen(Buff)+1);

   printf("write function has written %d no of bytes and the data written is %s",n_written,Buff);

   //close(handle);
}

void Parent_read(pid_t handle)
{
    printf("PARENT PROCESS: In Parent_read function\n");
    int i=0;
    int bytes_read = 0;
    char buffer[1024]= {'\0'};
    while (read(handle, buffer, sizeof(buffer)) > 0)
    {
        printf("PARENT PROCESS:: In while loop\n");
        printf("The character/string read from readend of readpipe (stdout) is %s",buffer);
    }
    close(handle);
}

外部程序如下所示

void printing()
{
  int c;
  do
    {
        c = getchar();
        printf("%c",c);
    } while ((c != EOF) && (c != '\n'));
}

void main()
{
  printing();
  printing();
}

请帮帮我!!!!!!!!!

2 个答案:

答案 0 :(得分:1)

在给定FILE *的第一次I / O调用(使用文件流函数)时,库决定流应该是行缓冲,块缓冲还是非缓冲。在你的情况下,当stdoutput启动时,它的stdoutput不是终端,所以流进入块缓冲模式,你的printf以缓冲区结束。

将您的主要功能更改为:

void main()
{
  setvbuf(stdout, NULL, _IONBF, 0);
  printing();
  printing();
}

你的printf调用会产生写入。

您还应该查看setvbuf手册页,并学会使用strace:

strace -ff -o test.log ./myprog

会产生两个日志文件(一个用于父项,一个用于孩子),可以让你看到什么 系统调用由每个程序进行。

答案 1 :(得分:-1)

事实上,正如Jerry Coffin评论的那样,你应该使用popen(某些系统也有p2open用于双向管道,一个在另一个系统中,另一个系统。)

如果你真的坚持自己这样做,你应该强烈考虑使用多路复用系统调用,如poll(或者可能是较旧的select)。然后,您将能够测试可以读取或写入的文件描述符,并采取相应的行动。