打开命名管道进行编写并在select()中使用它

时间:2014-07-22 12:46:08

标签: linux select named-pipes nonblocking fifo

我的总体目标是将报告信息传递到命名管道,如果(并且仅当)有一个读取器连接到该命名管道。如果没有读者,我想避免构建报告信息等。由于这是在通过select()处理其他数据流的情况下发生的,我想将命名管道添加到“准备好”的流中写作“。

所以,我想打开一个用于编写的命名管道,并且需要以某种方式将其提供给select(),以便select()只返回,以防在另一端有一个读者。命名管道。

通常情况下,如果没有阅读器,则open通话已挂起;遗憾的是,我无法向open提供select()操作 - 只有打开的文件描述符才有效。

为了获得一个不错的文件描述符,我正在创建一个虚拟阅读器(我打开命名管道来阅读自己),然后打开它进行写入,然后再次关闭虚拟阅读器:

dummy = os.open(fifoPath, os.O_RDONLY | os.O_NONBLOCK)
# ^^^ without the NONBLOCK, this will hang until another process is ready to write
fifo = os.open(fifoPath os.O_WRONLY)
os.close(dummy)

如果我现在打开另一个读者,他将收到我写入命名管道的内容,因此这方面有效。

但是现在select()总是将fifo作为准备写入返回,即使没有连接读者:

r, w, e = select.select([], [ fifo ], [])
print w[0]

这将始终同时打印fifo值。

写入命名管道也不会挂起,无论我写多少:

fifo.write('foo')

我写的数据因没有连接阅读器而丢失。

打开我的虚拟阅读器时,我正在传递旗帜O_NONBLOCK,因为否则这个开头也会挂起。我尝试了各种方法,但无法弄清楚如何正确地做到这一点。

有人能告诉我如何将写入命名管道与select()结合起来吗?

(上面的代码是在Python中,但我想这个问题并没有真正连接到Python而是Linux / Unix问题,所以我不会将这个问题标记为Python。)

1 个答案:

答案 0 :(得分:1)

请参阅man 7 fifo WRT管道应如何非阻塞地工作。

  

进程可以在非阻塞模式下打开FIFO。在这种情况下,即使在写入端没有打开任何人,只读打开也会成功,只读打开将因ENXIO(没有这样的设备或地址)而失败,除非另一端已经打开。 / p>      

在Linux下,打开FIFO进行读写将在阻塞和非阻塞模式下成功。 这可以用来打开FIFO进行写入,而没有可用的读取器。使用连接两端以便与自身通信的进程应该非常小心,以避免死锁。

这应该让你绕过dummy黑客。然而,将fd与select()一起使用,我认为是非首发。您可以改为使用select()的短暂超时,以便在主循环内以write()的间隔轮询fd,利用以下事实......

  

当进程尝试写入另一侧未打开读取的FIFO时,将向进程发送SIGPIPE信号。

...通过在调用之前将全局设置为true并在SIGPIPE处理程序中设置false以指示没有读者。

但是,Python可能是一个问题,因为你应该已经获得了这个信号,但显然不是。可能是因为dummy黑客(你真的要摆脱它)。

另一个也许更好的想法是为使用阻塞调用的fifo派一个处理程序,但也维护一个管道描述符到主进程的正常对(读/写)。其中一个(作者;即主要过程读取)可以与select()一起使用。叉子等待open()并在读卡器连接时发出主信号。

请注意,一旦您因为阅读器断开而达到EOF,您必须重新打开管道。不要继续使用相同的fd。

如果可行的话,我选择unix local socket超过fifo。