在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!
显然一次处理一个客户端。
当我删除IPC时 – 当我从父和子中删除管道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 */ } }