事實證明,與我對上述原始問題的評論相反,有一個直接的解決方案。
該解決方案假定所有讀取器和所有同一FIFO的寫入器共享內核緩衝區。這應該是實現FIFO的最合理,最直接的方式(考慮它們的行爲),所以我確實希望提供FIFO的所有系統都以這種方式運行。但是,這只是我的假設,不是任何保證。我還沒有在相關的POSIX標準中發現任何支持或抵觸這一點的內容。如果您發現其他情況,請注意。
的過程很簡單:
當一個客戶端意外消失,筆者再次打開的FIFO,不首先關閉原來的描述符。這個open()
將會阻塞,直到有新的讀取器可用,但由於原始文件描述符仍然是打開的,已經在FIFO中緩衝的數據將可供新讀取器使用。如果open()
成功,那麼作者只需關閉原始描述符,然後切換爲使用新描述符。
如果內核結構是共享的,FIFO緩衝區狀態將在寫入程序描述符之間共享,新讀取程序將能夠讀取以前讀取程序未讀的內容。
(請注意,筆者不知道客戶的變化之間的緩衝的數據量,因此是不知道在交換機發生的數據流中的點。)
我已經驗證了這個簡單的策略,在Linux上工作Ubuntu中x86_64上的3.8.0-35-通用內核以及x86_64上的2.6.9-104.ELsmp。
然而,我仍然完全要麼接受數據丟失,或改變協議達成一致,如通過巴西萊Starynkevitch在原來的問題評論建議。個人而言,我發現Unix域套接字(綁定到路徑名,例如/var/run/yourservice/unix
)是一個更好的選擇,因爲它允許多個併發客戶端沒有數據損壞(與FIFO不同)以及更加安全的協議。
我更喜歡Unix數據報套接字,每個數據報開始時的序列號和數據報長度。(這個長度有助於客戶端驗證它讀取整個數據報;我真的不希望任何操作系統截斷Unix數據報。)
通常,寫入程序向每個客戶端發送一些數據報,並在發送新消息之前等待確認那些。處理完數據報後,客戶端通過發送序列號給寫入器來確認數據報。 (請記住,這些是套接字,所以通信是雙向的。)這允許編寫者爲每個客戶端保留一些數據報,並且客戶端以正確的(序號)順序處理數據報或者亂序,使用多個線程。
重要的一點是每個數據報只有在它被處理後才被確認,而不是在它被接收後立即被確認。 (除了reader-> writer「acks」(確認),我還會支持「請重新發送」響應,以防客戶端使用太小的緩衝區來接收數據報。或者甚至可能是客戶不知道該怎麼處理的數據報「yuck」)
如果客戶端消失,作者知道所有未確認的數據報未被客戶端處理然而,並且可以將它們重新發送給另一個連接的客戶端或未來的客戶端。
有問題?
關閉並重新打開管道是否實用? – rici
你試過[民意調查(2)](http://man7.org/linux/man-pages/man2/poll.2.html)嗎? –
@BasileStarynkevitch:即使使用「poll()」,管道可能準備好寫入,然後,在寫入之前,讀者將死亡:數據丟失! – rodrigo