【问题标题】:Open named pipe for writing and use it in select()打开命名管道进行写入并在 select() 中使用它
【发布时间】:2014-09-13 07:11:20
【问题描述】:

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

所以,我想打开一个命名管道进行写入,并且需要以某种方式将其提供给 select(),以便 select() 仅在命名管道的另一端确实有读取器的情况下返回。

通常,如果没有阅读器,open 调用已经挂起;不幸的是,我无法对select() 执行open 操作——只有打开的文件描述符才有效。

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

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。)

【问题讨论】:

    标签: linux select named-pipes nonblocking fifo


    【解决方案1】:

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

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

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

    这应该可以帮助您绕过dummy hack。但是,我认为将 fd 与 select() 一起使用是行不通的。您可以改为使用select() 的短超时来促进在主循环内每隔一段时间使用write() 轮询fd,利用以下事实...

    当进程尝试写入另一端未打开以供读取的 FIFO 时,会向该进程发送 SIGPIPE 信号。

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

    Python 在这里可能是个问题,因为您应该已经收到了这个信号,但显然没有。这可能是因为dummy hack(你真的必须摆脱它)。

    另一个也许更好的主意是为使用阻塞调用的先进先出分叉一个处理程序,但同时也为主进程维护一对正常的管道描述符(读/写)。其中之一(作者;即由主进程读取)可以与select() 一起使用。 fork 在open() 上等待,并在读取器连接时发出 main 信号。

    请注意,一旦由于阅读器断开连接而到达 EOF,您必须重新打开管道。不要继续使用同一个 fd。

    如果可行的话,我会选择 unix local socket 而不是 fifo。

    【讨论】:

    • 1.我现在正在投票,并尽量避免这种情况(所以提议的方向是错误的;-)。 2.打开一个文件进行读/写是非阻塞的,因为这意味着有一个reader和一个writer,所以两个操作都不阻塞;但实际上这意味着select() 永远不会阻塞(如我所愿);所以可能这与我目前所处的情况相同。 3. 使用线程/进程可能是一种解决方案,但我不会将其与select() 混为一谈;然后我会为每个方面创建一个线程并使用适当的同步机制。但我更愿意坚持使用select() :-/
    • 嗯,当然你也可以吃蛋糕!我们都知道这就是编程的全部意义;)
    • 我可能没有收到 SIGPIPE,因为没有发送(Python 不会默默吞下)。我想它只有在没有 no 阅读器时才发送,但我的假人似乎在这方面算作现有阅读器,即使它已经关闭:-/ 所以我得出结论,我可能无法处理用select() 写信给fifo :-( 非常感谢您的回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 2012-07-31
    相关资源
    最近更新 更多