1

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

1) 父级将数据写入 pipe1 2) 子级从 pipe1 的重复端 (stdin) 读取数据 3) 子级对数据进行一些修改并将数据写回 stdout,该标准输出复制到 pipe2 的读取端 4) 父级尝试读取数据从管道2的读取端。

上述场景可以重复 n 次。

上述场景示例与示例 1) 父级写入 1 2) 子级读取 1 并进行修改并将 1(修改后)写入标准输出 3) 现在父级读取此数据并打印回来 4) 打印后,父级将 2 写入标准输入 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();
}

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

4

2 回答 2

2

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

将您的主要功能更改为:

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

您的 printf 调用将产生写入。

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

strace -ff -o test.log ./myprog

将产生两个日志文件(一个用于父级,一个用于子级),让您可以看到每个程序进行了哪些系统调用。

于 2012-04-06T08:35:10.447 回答
-1

确实,正如 Jerry Coffin 评论的那样,您应该使用popen(某些系统还具有p2open双向管道,一进一出)。

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

于 2012-04-04T05:29:03.600 回答