TCP並不總是「可靠」的?

2021-10-01 10:45:09 字數 1550 閱讀 8287

tcp 是可靠的?

傳送端通過呼叫send函式之後,資料流並沒有傳輸出去,資料會先儲存到套接字的傳送緩衝區中,通過網路協議棧決定何時傳送、如何傳送。當對應的資料傳送給接收端,接收端回應ack,這時儲存到傳送緩衝區的資料可以刪除了,但傳送端無法獲取對應資料流的ack情況(無法判斷對端是否接收到資料流),如果想知道,必須在應用層新增處理邏輯,例如顯示的報文確認機制。

從接收端來看,也不能保證ack過的資料被應用程式處理,因為資料需要從接收端拷貝,可能發生接收過程中程式突然崩潰。

所以,tcp協議沒有提供給上層應用程式過多的異常處理細節,反映鏈路異常的能力弱。(無人值守,自我恢復)

tcp連線之後,能感知鏈路方式只有read和write操作。

故障模式總結

2大類1.網路中斷造成的對端無fin包

網路中斷,tcp程式不能及時感到異常資訊,除非路由器發出icmp報文,說明目的網路或主機不可達,這個時候通過read或write呼叫就會返回unereachable錯誤

如果沒有icmp報文的情況下,tcp程式不能理解應到連線異常,如果程式阻塞到read呼叫上,程式將無法恢復正常。不過可以給read操作設定超時來解決。

如果先呼叫write傳送資料流,接下來阻塞在read呼叫上。tcp協議棧將傳送緩衝區的資料發出去,大概重傳12次、合計時間為9分鐘,協議棧標識會連線異常,這是阻塞的read呼叫會返回timeout錯誤資訊,如果程式還往這條連線寫資料,寫操作會立即失敗,返回乙個sigpipe訊號給應用程式。

系統崩潰造成對端無fin包

系統崩潰,比如斷電,網路連線上來不及發出任何東西。這個和通過系統殺死應用程式不同的是,沒有fin包發出來。

情況1:沒有icmp報文情況下,tcp程式只能通過read和write呼叫得到網路連線異常資訊,常見的是超時錯誤。

情況2:系統崩潰之後又重啟,當重傳的tcp分組到達重啟後的系統,由於沒有tcp分組對應的連線資料,系統會返回乙個rst重置分節,tcp程式通過read和write呼叫可以對rst進行錯誤處理。

如果是阻塞read呼叫,會立即返回乙個錯誤,錯誤為連線重置(connection reset)

如果是一次write操作,會立即失敗,應用程式會返回乙個sigpipe訊號

對端有fin包發出

如果有fin包發出,可能場景是對端呼叫了close或shutdown顯示關閉連線,也可能是對端應用程式崩潰,作業系統核心代為清理所發出的,從應用程式角度來看,無法區分是那種情形。

阻塞的read操作完成資料讀取之後,fin包會通過乙個eof來完成通知,此時,read呼叫返回值為0。read收到fin包之後不會立即返回,他會往接收緩衝區放置乙個eof符號,之前已經在接收緩衝區的有效資料不會受到影響。

向乙個已關閉連線連續寫,最終導致 sigpipe

如果在服務端讀取資料並處理過程中,突然殺死伺服器程序,我們會看到客戶端很快也會退出,並在螢幕上列印出「connection reset by peer」的提示。

總結tcp異常分兩大類:一類是對端無fin包,需要通過巡檢或超時來發現;

另一類是對端無fin包,需要通過巡檢或超時來發現,另一類是對端有fin包發出,需要通過增強read或write操作異常處理,幫助發現異常。

TCP並不總是「可靠」的?

1.當對方意外崩潰後 如斷電或網路中斷 並且沒有發出fin包時,處於傳送端無法得知這種情況,處於傳送緩衝區的資料會不斷向對方傳送,但由於對方離開會不斷因為超時重傳,重傳12次左右 大概9分鐘 依然沒有響應就會返回乙個超時通知 如果傳送端此時有乙個read操作會讀取到這個訊號,但如果在之後你繼續通過這...

新的並不總是最好的

不知道大家是否接受這種觀點 新的並不總是最好的 new doesn t always mean better.我們在平時習慣於接受新的產品,立刻放棄舊的,我們習慣於對新產品的追逐,新產品給我們帶了對未來希望的憧憬,它給我們煩悶的生活注入新鮮,讓我們為之一振,讓我們感受到我們還活在不斷前進的社會中,與...

TCP的可靠傳輸

可靠傳輸 能夠有序的都到達接受方 tcp使用滑動視窗 學習三個機制 超時重傳 快速重傳 選擇確認 累計確認 先了解背景 超時重傳很簡單 超時重傳的時間設定是個難點 簡單來說時依據多個往返時間確認平均往返時間,超時重傳設定比平均往返時間要長一點,記住超時時間時動態設定不斷變化的 以後有必要的時候來了解...