2011-05-10 236 views
15

考慮以下情形:防止FIFO關閉FIFO

一個FIFO命名創建test。在一個終端窗口(A)中運行cat <test,並在另一個終端窗口(B)中運行cat >test。現在可以在窗口B中寫入並在窗口A中獲取輸出。也可以終止進程A並重新啓動它,並仍然可以按照懷疑使用此設置。但是,如果您在窗口B中終止進程,那麼B(就我所知)將通過FIFO發送EOF來處理A並終止該進程。實際上,如果您運行的流程不會在EOF上終止,您仍然無法使用您重定向到流程的FIFO。我認爲這是因爲這個FIFO被認爲是關閉的。

有沒有辦法解決這個問題?

爲什麼我遇到這個問題的原因是因爲我想發送命令到在屏幕會話中運行的我的Minecraft服務器。例如:echo "command" >FIFO_to_server。這可能是通過自己使用屏幕來完成的,但我對屏幕不太舒服,我認爲只使用管道的解決方案會更簡單和更清晰。

回答

26

A正在讀取文件。當它到達文件末尾時,它停止閱讀。這是正常行爲,即使該文件恰好是fifo。你現在有四種方法。

  1. 更改閱讀器的代碼,使其在文件結束後繼續閱讀。這就是說輸入文件是無限的,並且到達文件的末尾只是一個幻想。對你來說不實用,因爲你不得不改變我的服務器代碼。
  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服務器。

+0

不幸的是,'tail'等待EOF,因此它不會逐行傳遞管道中的內容。 – pabouk 2013-08-22 16:42:34

+2

@pabouk感謝您指出這個錯誤:'tail -n 1 -f'會跳過在它啓動之前可用的輸入或使其可用的速度超過其可讀的速度。我打算寫'tail -n +1 -f',它馬上開始輸出。 – Gilles 2013-08-22 17:03:55

+2

謝謝。我曾嘗試過,但'-n + 1'沒有按預期工作。現在,您已確認這是正確的方式,我進一步檢查了問題,並意識到問題出現在「tail」標準輸出的塊緩衝(而不是默認行緩衝)中。逐行管道的解決方案:'stdbuf -oL tail -n +1 -f client_pipe |命令' – pabouk 2013-08-22 17:55:41

6

啓動一個進程,使FIFO保持開放狀態並保持無限期運行。這將防止讀者看到文件結束的情況。