在C中使用用于父子IPC的管道会使程序阻塞

时间:2009-02-22 19:45:52

标签: c pipe ipc interprocess

我正在编写一个服务器,当fork接受套接字连接时,fork()关闭子进程。

当孩子与客户沟通时,它必须将一些信息发送回父母。我正在使用烟斗来实现这一目标。

问题在于,当我尝试做父子IPC时,父母在读取孩子的输入时会阻止。这意味着,即使孩子们同时运行,他们也只能一次一个地处理,因为他们都在等待父母。

我的代码看起来像这样(为简洁起见,删除了错误检查):

/* loop: wait for clients to connect */
for(;;) {

  pipe(write_to_parent); /* create pipe between parent and child */
  pipe(write_to_child);  /* create pipe between parent and child */

  newsockfd = accept(...);

  pid = fork();

  if (pid == 0) { /* child process */
      close(write_to_parent[0]);
      close(write_to_child[1]);

     printf("Connected!\n");

     while ((rc = recv(newsockfd, ...)) > 0) {
         /* process socket request */

         /* write stuff to parent that is related to what we recv'd from client */
         rc = write(write_to_parent[1], &buf, 1024);
     }

     printf("Disconnected!\n");

     exit(0);
  } else { /* parent */

      close(write_to_parent[1]);
      close(write_to_child[0]);

       while (read(write_to_parent[0], &buf, 1024) > 0) {
           /* accept data from child process, and do some processing */
       }
  }
}

所以我的问题是,我该如何解决这个问题?如何让父母使用管道与孩子进行沟通,使其不会阻塞?

管道是否可能,或者我应该使用共享内存(我猜是信号量)还是消息队列? (我读过这篇文章:Comparing Unix/Linux IPC但很难找到实际完成这些任务的例子。)

更多详情:

我有一个执行以下操作的测试程序: 1.连接到服务器 2.睡觉(5) 3.断开与服务器的连接

当我运行此程序的2个实例时,服务器输出:

connected!
  // pause for 5 seconds
disconnected!
connected!
  // pause for 5 seconds
disconnected!

显然每次处理一个客户端。

当我删除I​​PC时 - 当我从父级和子级中删除管道read()和write()时,我得到了这个:

connected!
connected!
  // pause for 5ish seconds
disconnected!
disconnected!

这就是我想要的!

有关如何实现这一目标的任何想法? (或者我应该以解决这个问题的方式做出改变?)

(编辑:这是网络类任务的一部分。我们正在实施一个P2P协议,使用集中式服务器来管理同行。我们可以使用任何语言,我想我会给它一个旋转C。)

1 个答案:

答案 0 :(得分:2)

我在下面写了答案,在重读你的问题时,注意到我完全错过了你的实际问题。但是,它在任何情况下都可能是有用的信息。

要回答您的并发父问题,您需要让父设置一个select()循环来随时处理来自其任何子项的可能响应。你需要:

  • 跟踪有多少孩子开放
  • 每个孩子
  • 保留一组管道
  • 使用带select()的循环来接受传入连接(因为它们可能随时发生)以及来自任何子节点的传入数据
  • 使用waitpid()收获已终止
  • 的儿童

这项技术功能强大,但需要大量记账才能正确设置。


父进程中打开的文件句柄默认在子进程中继承。问题可能是两者父级和子级管道的写入端仍然打开,所以当父级从管道读取时,它将永远不会看到它的结束。在您开始阅读close(write_to_parent[1])之前,请立即尝试在父级中使用write_to_parent[0]。所以:

} else { /* parent */
     close(write_to_parent[1]);
     while (read(write_to_parent[0], &buf, 1024) > 0) {
         /* accept data from child process, and do some processing */
     }
}