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

我正在编写一个服务器,当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 */ } } } 

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

这甚至可以用管道,或者我应该使用共享内存(我猜的是信号量)还是消息队列? (我读过这篇文章: 比较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中给它一个旋转。)

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

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

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

这种技术function强大,但需要大量的簿记才能正确设置。


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

 } 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 */ } }