如何等待命名管道的另一端打开?
Posted
技术标签:
【中文标题】如何等待命名管道的另一端打开?【英文标题】:How to wait for the other end of a named pipe to be open? 【发布时间】:2018-02-09 00:57:10 【问题描述】:我想使用 2 个命名管道(a2b
和 b2a
)在 2 个进程(A
和 B
)之间交换数据,如下所示:
-
进程
A
使用mkfifo(3)
创建a2b
和b2a
管道。
进程A
启动进程B
(使用fork()
、exec*()
甚至system()
)
A
等到 B
open()
s a2b
和 b2a
A
write()
s 数据到 a2b
B
read()
s 数据来自a2b
B
write()
s 数据到b2a
A
read()
s 数据来自 b2a
如何让进程A
等到进程B
open()
s 命名管道的另一端? -- 即如何实施第 3 步?
编辑 1:正如@EJP 所述,可以使用读/写/选择来实现第 3 步。但是,我想知道是否有其他方法。
【问题讨论】:
B 最好先给 A 写点东西,只是一条 Hello 消息。然后 A 可以阻塞相应的读取,或管道上的select()
以提高可读性。
我同意这是一种可能的方法。但是,我不想使用读/写来确定另一端是否打开。 (我应该在我的帖子中说明这一点)
所以你想要告诉你另一个进程何时在其私有地址空间中打开了文件描述符?我认为这是不可能的,除了轮询 /proc/PID_PROCESSB/fd 和寻找管道。否则,您可以要求 PROCESS B 在准备好时向您发出信号,但据我所知,没有机制可以通过 fifos 传达此信息
有趣。你能用一些代码发布答案吗? (即为命名管道轮询/proc/process_b/fd
。TBH 我不喜欢使用信号)
UNIX 域套接字可能更合适。您可以使用select()
,然后检查是否出现accept()
。当“pipe”的另一端(socket)连接时,select in this end 返回,你可以检查一下。
【参考方案1】:
POSIX open 的行为是为 FIFO 指定的。如果您使用的是 Linux,man 7 fifo
有一些很好的讨论:
内核为每个特殊的 FIFO 维护一个管道对象 由至少一个进程打开的文件。 FIFO 必须打开 在数据可以传递之前的两端(读取和写入)。 通常,打开FIFO会阻塞,直到另一端也打开。
进程可以在非阻塞模式下打开 FIFO。在这种情况下,打开 即使没有人在写入端打开,for read-only 也会成功 然而,ENXIO 只写打开失败(没有这样的设备或 地址)除非另一端已经打开。
所以你有两个选择:
-
使用阻塞模式,
open
调用将阻塞直到另一端打开,或者
使用非阻塞模式并继续调用open
,直到成功。
如果您的要求允许,您可以完全跳过命名管道 (FIFO),而只需使用 pipe
。子进程将打开的文件描述符继承到管道的每一端,并且可以根据需要使用其中一个(不要忘记关闭不需要的描述符)。
但是,考虑到您的最终目标是双向通信,我是否可以建议一个 (unix domain) socket
和一些 IO 多路复用策略(select
、poll
、epoll
、kqueue
等.)?
【讨论】:
一个关键点是两个进程必须合作,以相同的顺序打开两个 FIFO——它们必须在b2a
之前打开 a2b
,反之亦然。如果一个打开a2b
,另一个先打开b2a
,那么它们就会陷入僵局——第一个在等待另一个打开a2b
,而第二个在等待另一个打开b2a
,两者都挂起直到另一个做预期的事情。以上是关于如何等待命名管道的另一端打开?的主要内容,如果未能解决你的问题,请参考以下文章
Unidac连接出错:命名管道提供程序:管道的另一端上无任何进程.
sql server 2008启动时:已成功与服务器建立连接,但是在登录过程中发生错误。(provider:命名管道提供程序,error:0-管道的另一端上无任何进程。)(Microsoft SQL