2013-03-21 56 views
1

我正在使用C編寫的Linux客戶端服務器應用程序中使用TCP將數據複製到多個從屬副本,我想知道如何處理某些副本的意外臨時關閉(它可能是unix進程崩潰或硬件掉電)。從丟失的TCP連接中恢復傳輸

當我向內核發出write()系統調用時,成功返回意味着數據被複制到套接字,但並不意味着接收端得到了的數據。如果目標電源關閉後再通電,則數據必須從丟失數據的位置重新發送(在建立新的TCP連接後)複製副本。假設我正在處理大量數據,並且不保留已發送的數據(即write()系統調用返回成功)。我只保留待發送的數據。

當副本從意外關閉中恢復並再次連接時,如何從內核獲取已寫入套接字的數據,但在目標主機上不是'ack' - 尚未?或者換句話說,我如何從丟失TCP連接中恢復並重新建立客戶端和服務器之間從停止點開始的傳輸?

回答

1

TCP會照顧需要的TCP序列號,就可以沒有太大的利用者在應用層面

您需要在應用層面的一些順序控制。

在你的情況下,你可以給你發送的每個數據塊分配一個數字。目標需要持續跟蹤它收到的最後一個塊號。在意外關機啓動時,目標需要傳回它處理的最後一個塊號,然後開始從那裏發送。

如何從內核獲取已寫入套接字的數據,但在目標主機上沒有「ack」 - 請求?

即使你可以,這還不夠。目標主機很可能會已經獲得確認」的數據,但ACK可能會丟失無論出於何種原因,或從未發送,但目標應用程序可能接收和處理數據的罰款。所以如果你在這種情況下使用TCP序列號,你最終會得到重複的數據。

另一種情況是,TCP發回了數據的ack,目標應用程序在讀取數據時崩潰/關閉,但恰好在它將數據寫入磁盤之前。所以你最終會丟失數據。

+0

[預寫日誌協議](http://en.wikipedia.org/wiki/Write-ahead_logging)用於確保安全。 – 2013-03-21 15:04:50

2

您需要在TCP之上添加另一個抽象級別。在發送每一段數據之後(TCP確保它將完整無損地依次到達),讓另一端的進程發送它自己的一種ACK,用你自己的更高級別的協議(不管是什麼 - 不管它是什麼 - ACK \ 0「,」GOT \ n「或其他)。在另一邊(發起人),閱讀這些數據。如果它沒有錯誤地通過,一切都很好。如果出現錯誤 - 請檢查類型。如果您獲得ECONNRESET,那意味着遠端已經死亡。從這裏,你可以做出相應的迴應。等到你可以重新連接,並重新發送數據。

+0

如果我必須在TCP本身上實現我自己的TCP,這讓我覺得在這種情況下UDP可能更好。 – Nulik 2013-03-21 14:50:08

+1

@Nulik:不! (請不要使用UDP!請!)。 UDP並不保證任何東西*永遠*在任何地方得到*,或者它以*任何順序到達那裏,或者它甚至被*發送*在第一位!這不是TCP之上的TCP,而是一個利用了TCP所有特性的小型應用程序級協議。請不要重新實施TCP。數百名專家已經完成了操作系統的實施。不要試圖重做他們的工作。 – Linuxios 2013-03-21 14:52:14

2

沒有辦法通過標準API來做你想做的事情。

一個解決辦法是讓你的客戶定期發送回的運行總計收到並覈實寫入到磁盤的字節,然後不斷的發送緩衝區,但在服務器上未確認數據。然後,當客戶端重新連接時,它會發送最後一個好計數,並且服務器知道從哪裏開始重新發送。