简体   繁体   English

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

[英]How to implement two way communication between child and parent processes using pipes which involves multiple read and writes

I have implement a scenario which involves two way communication between child and parent processes.我已经实现了一个涉及子进程和父进程之间的双向通信的场景。 The child process uses execvp to launch another c program (say XYZ).子进程使用 execvp 启动另一个 c 程序(比如 XYZ)。 Parent writes data at one end of pipe1 and other end of pipe1 is duplicated to child's stdin. Parent 在 pipe1 的一端写入数据,pipe1 的另一端被复制到 child 的标准输入。 so child reads this data, performs some manipulations and writes data back to stdout.所以孩子读取这些数据,执行一些操作并将数据写回标准输出。 This stdout is duplicated to write end of pipe2 and now parent reads from read end of pipe2.此标准输出被复制到 pipe2 的写入端,现在父级从 pipe2 的读取端读取。 The external program XYZ is not to be modified.外部程序 XYZ 不可修改。 The sequence to be followed is要遵循的顺序是

1) parent writes data to pipe1 2) child reads data from duplicated end (stdin) of pipe1 3) child does some modifications to data and writes data back to stdout, which is duplicated to read end of pipe2 4) parent tries to read data from read end of pipe2. 1) parent 将数据写入 pipe1 2) child 从 pipe1 的重复端 (stdin) 读取数据 3) child 对数据进行一些修改并将数据写回 stdout,stdout 被复制到 pipe2 的读取端 4) parent 尝试读取数据从 pipe2 的读取端开始。

The above scenario can be repeated n number of times.上面的场景可以重复n次。

Example of above scenario with example 1) parent writes 1 2) child reads 1 and does modification and writes 1 (after modifcations) to stdout 3) Now parent reads this data and prints back 4) after printing, parent writes 2 to the stdin 5) continues as above.....以上场景示例 1) 父级写入 1 2) 子级读取 1 并进行修改并将 1(修改后)写入标准输出 3) 现在父级读取此数据并打印回 4) 打印后,父级将 2 写入标准输入 5 ) 继续如上.....

The problem i am facing is parent is not able to read data from read end of pipe2.我面临的问题是父级无法从 pipe2 的读取端读取数据。 Its literally hanging out.它实际上是闲逛。

Imp Note: I have not closed the write handle of pipe1 because, i need to write data again. Imp 注意:我没有关闭 pipe1 的写句柄,因为我需要重新写入数据。 If i close the handle, i cannot reopen it, as it is not supported by pipes.如果我关闭手柄,我无法重新打开它,因为它不受管道支持。

The code is as shown below代码如下图

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

The external program is as shown below外部程序如下图

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

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

Please help me !!!!!!!!!请帮我 !!!!!!!!!

On the first I/O call (using file stream functions) for a given FILE *, the library decides wether the stream should be line buffered, block buffered, or unbuffered.在针对给定 FILE * 的第一次 I/O 调用(使用文件 stream 函数)时,库决定 stream 应该是行缓冲、块缓冲还是非缓冲。 In your case, when stdoutput starts, it's stdoutput is not a terminal, so the stream goes in block buffered mode, and your printf ends in a buffer.在您的情况下,当 stdoutput 启动时,它的 stdoutput 不是终端,因此 stream 进入块缓冲模式,而您的 printf 在缓冲区中结束。

Change your main function to:将您的主要 function 更改为:

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

And your printf call will produce writes.您的 printf 调用将产生写入。

You shoud also look at the setvbuf man page, and learn to use strace:您还应该查看setvbuf手册页,并学习使用 strace:

strace -ff -o test.log ./myprog

will produce two log fil (one for the parent, one for the child) that will let you see what system call are made by each program.将产生两个日志文件(一个给父级,一个给子级),让您看到每个程序进行了哪些系统调用。

Indeed, as Jerry Coffin commented, you should use popen (some systems also have a p2open for bidirectional piping, one in, another out).确实,正如 Jerry Coffin 评论的那样,您应该使用popen (某些系统也有用于双向管道的p2open ,一个输入,另一个输出)。

If you really insist on doing it by yourself, you should strongly consider using a multiplexing system call like poll (or perhaps the older select ).如果你真的坚持自己做,你应该强烈考虑使用像poll这样的多路复用系统调用(或者可能是更老的select )。 Then you'll be able to test which file descriptor can be read or written, and act accordingly.然后您将能够测试可以读取或写入哪个文件描述符,并采取相应的行动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM