【问题标题】:Prevent FIFO from closing / reuse closed FIFO防止 FIFO 关闭/重用已关闭的 FIFO
【发布时间】:2011-08-22 21:04:36
【问题描述】:

考虑以下场景:

创建了一个名为 test 的 FIFO。在一个终端窗口 (A) 我运行 cat <test 并在另一个 (B) cat >test。现在可以在窗口 B 中写入并在窗口 A 中获取输出。也可以终止进程 A 并重新启动它,并且仍然可以按照怀疑使用此设置。但是,如果您在窗口 B 中终止进程,B 将(据我所知)通过 FIFO 向进程 A 发送 EOF 并终止它。

事实上,如果您运行的进程没有在 EOF 上终止,您仍然无法使用重定向到该进程的 FIFO。我认为这是因为这个 FIFO 被认为是关闭的。

有没有办法解决这个问题?

我遇到这个问题的原因是因为我想向在屏幕会话中运行的 minecraft 服务器发送命令。例如:echo "command" >FIFO_to_server。这可能通过单独使用 screen 来实现,但我对 screen 不太满意,我认为仅使用管道的解决方案会更简单、更清洁。

【问题讨论】:

    标签: unix named-pipes eof fifo


    【解决方案1】:

    A 正在读取文件。当它到达文件末尾时,它会停止读取。这是正常行为,即使该文件恰好是一个 fifo。您现在有四种方法。

    1. 更改阅读器的代码,使其在文件结束后继续阅读。也就是说输入文件是无限的,到达文件末尾只是一种错觉。对您来说不实用,因为您必须更改 minecraft 服务器代码。
    2. 应用 unix 哲学。你有一个不同意协议的作者和一个读者,所以你插入了一个连接他们的工具。碰巧,在 unix 工具箱中有这样一个工具:tail -ftail -f 即使在看到文件结尾之后也会继续从其输入文件中读取。让您的所有客户端与管道对话,并将tail -f 连接到 minecraft 服务器:

      tail -n +1 -f client_pipe | minecraft_server &
      
    3. As mentioned by jilles,使用一个技巧:管道支持多个写入器,并且只有在最后一个写入器离开时才会关闭。所以请确保有一个永远不会消失的客户。

      while true; do sleep 999999999; done >client_pipe &
      
    4. 问题在于服务器基本上是为处理单个客户端而设计的。要处理多个客户端,您应该更改为使用套接字。将套接字视为“元管道”:连接到套接字会创建一个管道,一旦客户端断开连接,该特定管道就会关闭,但服务器可以接受更多连接。这是干净的方法,因为如果两个客户端碰巧同时连接(使用管道,它们的命令可以穿插),它还可以确保您不会混淆数据。但是,它需要更改 minecraft 服务器。

    【讨论】:

    • 不幸的是,tail 等待 EOF,因此它不会逐行传递管道中的内容。
    • @pabouk 感谢您指出这个错误:tail -n 1 -f 会跳过在开始之前可用的输入,或者比读取速度更快。本来想写tail -n +1 -f,马上就开始输出了。
    • 谢谢。我之前尝试过,但-n +1 没有按我的预期工作。现在,当您确认这是正确的方法时,我进一步检查了问题并意识到问题出在tail 的标准输出的块缓冲(而不是默认的行缓冲)中。逐行配管解决方案:stdbuf -oL tail -n +1 -f client_pipe | command
    • 有一种更简单的方法可以确保管道至少有一个写入器:让读取器以读写模式打开它:minecraft_server <>client_pipe &
    【解决方案2】:

    启动一个进程,使 fifo 保持打开以供写入并无限期地运行。这将防止读者看到文件结束的情况。

    【讨论】:

      【解决方案3】:

      来自this answer -

      在 Linux 等某些系统上,命名管道 (FIFO) 上的 会打开命名管道而不阻塞(无需等待其他进程打开另一端),并确保管道结构保持活动状态。例如在:

      所以你可以这样做:

      cat <>up_stream >down_stream
      
      # the `cat pipeline keeps running
      echo 1 > up_stream  
      echo 2 > up_stream
      echo 3 > up_stream
      

      但是,我找不到有关此行为的文档。所以这可能是特定于某些系统的实现细节。我在 MacOS 上尝试了上述方法,它可以工作。

      【讨论】:

        【解决方案4】:

        您可以通过在“mkfifo yourpipe”中用分号在括号中添加您需要的内容来在管道中添加多个输入:

        (cat file1; cat file2; ls -l;) > yourpipe
        

        【讨论】:

          猜你喜欢
          • 2014-12-13
          • 2013-06-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-17
          • 1970-01-01
          • 2015-09-25
          • 2012-01-14
          相关资源
          最近更新 更多