2017-04-03 43 views
-1

我在這裏發現了很多線程,詢問如何在寫入之後刷管道而不關閉它。 在每一個線程中,我可以看到不同的建議,但我找不到明確的解決方案。沖洗管道不關閉C

這裏是一個快速摘要:

  1. 最簡單的方式,以避免讀取管道阻塞是寫即讀字節的確切數量。

  2. 它也可以通過使用ptmx而不是管道來完成,但人們說這可能會很多。

注:這是不可能使用的fsync與管道

是否有其他更有效的解決方案?

編輯:當發送者想要寫的n個字符,但客戶端讀取米字符(其中,M> N)

沖洗將是方便的。客戶端將阻止等待另一個m-n個字符。如果發件人希望再次與客戶端通信,則無需關閉管道,只需發送確切數量的字節就可以成爲錯誤的良好來源。

接收器操作這樣的,它不能被修改:

while((n=read(0, buf, 100)>0){ 
    process(buf) 

使發送者希望得到處理:「文件1」和「文件2」爲將要:

write(pipe[1], "file1\0*95", 100); 
write(pipe[1], "file2\0*95", 100); 

我正在尋找一種方式來做類似的事情(不必使用\ n作爲分隔符):

write(pipe[1], "file1\nfile2", 11); //it would have worked if it was ptmx 

(使用讀取和寫入)

+2

這聽起來很像[X-Y問題](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)。一般來說,不需要衝洗管道,那麼真正的問題是什麼? –

+0

你是什麼意思的「點」? –

+0

@John:我指的是僞終端主/從。我已更新原始帖子。 –

回答

1

沖洗的fflush()意義上與管道無關,因爲它們不表示爲C流。因此沒有用戶級緩衝區來刷新。同樣,fsync()也與管道無關,因爲數據沒有後端存儲。成功寫入管道的數據存在於內核中,並且只有在內核中才會成功讀取,因此fsync()無法工作。總體而言,沖洗/同步僅適用於涉及中間存儲的情況,管道不屬於這種情況。

澄清之後,您的問題似乎是建立通過管道進行通信的消息邊界。你是正確的,關閉管道的寫入結束將發出一個邊界 - 不僅僅是一條消息,而是整個通信流 - 但當然這是最終的。你也沒有固有的信息邊界是正確的。不過,你似乎是從這裏一個誤解,至少有些工作:

最簡單的方式,以避免讀取上阻塞管道是寫 所讀取字節的確切數量。

[...]

當發送者想寫入 個字符但客戶端讀取m個字符(其中m> n)時,刷新會很方便。客戶端 將阻止等待另一個m-n個字符。

讀者是否會阻止完全取決於讀者如何實施。特別是,系統調用不保證在返回之前傳送所請求的字節數。在某些情況下,它可以並將執行簡短的閱讀。雖然細節沒有詳細說明,但至少可以傳輸一個字符而不會阻塞,但不能傳輸請求的整個數字,您通常可以依靠簡短的閱讀。類似的情況也適用於write(2)。因此,避免read()阻塞的最簡單方法是確保您至少寫入一個字節到用於該read()調用的管道傳輸。

事實上,人們通常從相反的方向來看這個問題:需要確定接收特定數量的字節,因此不得不將短讀取作爲併發症進行處理(將由循環執行read())。您也需要考慮這一點,但您的客戶在您描述的情況下不太可能阻止您的好處;它只是不是你認爲的問題。

然而,在任何類型的流通信中都存在固有的消息邊界問題,您需要處理它。有幾種方法;其中最常用的是

  • 固定長度消息。接收器可以讀取,直到它成功傳輸所需的字節數;涉及的任何阻塞都是適當且需要的。採用這種方法,你所假設的場景根本不會出現,但作者可能需要填充其消息。

  • 分隔郵件。接收器然後讀取,直到它發現它已收到一個消息分隔符(例如換行符或空字節)。在這種情況下,接收方需要準備好消息邊界不會與read()調用傳輸的字節序列對齊的可能性。通過關閉通道標記消息的結尾可以被認爲是這種替代方案的特例。

  • 嵌入的消息長度元數據。這可以採取多種形式,但最簡單的一種方法是將消息構造爲固定長度的整數消息長度字段,然後是消息數據的該字節數。讀者在每一點都知道它需要讀取多少字節,所以它不會不必要地阻塞。

這些可以單獨使用或組合使用來實現應用層協議,以便在進程之間進行通信。自然,通信雙方必須就通信協議的細節達成一致才能成功。

+0

感謝您的回覆。我在原來的問題中增加了一些註釋,但是我所看到的是這樣的答案:「它可以並且將在某些情況下執行一個簡短的閱讀」這些情況是哪些? –

+0

@AntonisParagas,我已經在最大程度上回答了我的答案:「儘管**的細節沒有說明,但通常您可以依靠簡短的閱讀,至少有一個角色可以傳輸而不會阻塞,但不能要求的整個號碼。「也就是說,read()通常不會傳輸至少一個字節。 –