2012-06-28 80 views
2

如果我在兩個進程(或兩個線程)之間共享一個套接字,並且在它們中都嘗試發送阻塞的大消息(大於下劃線協議緩衝區),是否保證這兩條消息將按順序發送?或者它可能在內核中交錯消息?套接字發送併發保證

我主要關注TCP over IP行爲,但知道它是否根據套接字協議而變化將會很有趣。

回答

4

你在問,如果你的消息A,B在同一個套接字上,A是保證在B之前到達的?對於SOCK_STREAM(例如TCP)和SOCK_SEQPACKET(幾乎從不使用)套接字,答案是不合格的。對於因特網上的SOCK_DGRAM(即UDP數據包),答案是否定的:數據包可以由網絡重新排序。在單個主機上,unix域數據報套接字將(在我所知的所有系統上)保留排序,但我不相信這是由任何標準保證的,我確信存在邊緣情況。

或等待:也許你問是否兩個進程寫的消息不會混合?是的:單個系統調用(write/writev/sendto/sendmsg)總是以原子方式將其內容放入文件描述符中。但很顯然,如果你或者你的圖書館把這些寫入多個電話,你會失去這種保證。

1

對於UDP,如果兩個線程同時寫入套接字句柄,則這兩個消息將作爲單獨的數據報發送。如果數據包大於MTU,可能會經歷IP碎片化,但結果數據報將被接收方保留並正確重新組裝。換句話說,除了與UDP相關的常見問題(數據報重新排序,數據包丟失等)外,您對UDP安全。

對於基於流的TCP,我不知道。你的問題基本上是要求相當於「如果兩個線程試圖寫入相同的文件句柄,文件是否仍然可讀?」我其實不知道答案。

你能做的僅僅是使用一個線程安全鎖(互斥體)守護髮送/寫入套接字調用,只線程可以寫在一個時間插槽上最簡單的事情。

對於TCP,我會建議有一個專用線程來處理所有socket io。然後創建一個方法,讓工作流中的消息可以異步地排隊到套接字線程以供它發送。套接字線程也可以處理recv()調用,並在套接字連接被遠程端終止時通知其他線程。

+0

我寫信給來自2個不同進程的套接字,並且你遇到了我的問題:避免在進程之間傳遞消息(如果我有一個單獨的寫作進程)時,最好只是通過套接字發送它們。我可以將寫入與信號同步,但如果內核無論如何都會這麼做,我寧願避免這種麻煩(這是我的問題的關鍵)。 – lvella

+0

我在試圖找出sendto()是否是線程安全的時候遇到了這個答案。那是這種情況?如果是這樣,太棒了! – fluffy

0

如果你嘗試在超過了基礎緩衝區大小流套接字發送大郵件,這幾乎是保證你,你會得到一個簡短的寫 - 寫,或者將通話將只寫部分數據(儘可能將適合在緩衝區),然後返回記的金額,讓你做的其餘數據的另一個寫入。

如果您在多個線程或進程中執行此操作,則每個寫入(或發送)都將自動將一小部分消息原子地寫入發送緩衝區,但隨後的寫入操作可能以任何順序發生,結果是正在發送的大緩衝區將被交織。另一方面,如果您在DGRAM套接字上發送消息,則整個消息將以原子方式發送(作爲單個第4層數據包,可能會被協議堆棧的較低層碎片化和重新組合),或者您會得到一個錯誤(EMSGSIZE Linux或其他UNIX變體)

+0

如果我們使用MSG_WAITALL標誌寫入大消息,該怎麼辦?這保證是原子嗎? – FaceBro

+0

'MSG_WAITALL'不支持寫入,只能讀取。 –

+1

不,它可以用於讀取和寫入。 – FaceBro