TCP-IP詳解:超時重傳機制
參考教材:TCP-IP Guide
超時重傳是TCP保證資料傳輸可靠性的又一大措施,本文主要介紹重傳TCP報文的兩大舉措:超時重傳和快速重傳
超時重傳機制
超時重傳指的是,傳送資料包在一定的時間週期內沒有收到相應的ACK,等待一定的時間,超時之後就認為這個資料包丟失,就會重新發送。這個等待時間被稱為RTO.
檢測丟失segment的方法從概念上講還是比較簡單的,每一次開始傳送一個TCP segment的時候,就啟動重傳定時器,定時器的時間一開始是一個預設的值(Linux 規定為1s),隨著通訊的變化以及時間的推移,這個定時器的溢位值是不斷的在變化的,有相關演算法計算RTO[參考:文章....],如果在ACK收到之前,定時器到期,協議棧就會認為這個片段被丟失,重新傳送資料。
TCP在實現重傳機制的時候,需要保證能夠在同一時刻有效的處理多個沒有被確認的ACK,也保證在合適的時候對每一個片段進行重傳,有這樣幾點原則:
1 . 這些被髮送的片段放在一個視窗中,等待被確認,沒有確認不會從視窗中移走,定時器在重傳時間到期內,每個片段的位置不變,這個地方其實在滑動視窗的時候也有提到過
2 .只有等到ACK收到的時候,變成傳送並ACK的片段,才會被從視窗中移走。
3 .如果定時器到期沒有收到對應ACK, 就重傳這個TCP segment
重傳之後也沒有辦法完全保證,資料段一定被收到,所以仍然會重置定時器,等待ACK,如果定時器到期還是沒有收到ACK,繼續重傳,這個過程重傳的TCP segment一直留著佇列之內。
舉個重傳的例子:
1. Server 傳送80個位元組 Part1,seq = 1
2. Server 傳送120個位元組Part2,Seq = 81
3. Server傳送160個位元組Part3,Seq = 201,此包由於其他原因丟失
4. Client收到前2個報文段,併發送ACK = 201
5. Server傳送140個位元組Part4, Seq = 361
7. Server收到Client對於前兩個報文段的ACK,將2個報文從視窗中移除,視窗有200個位元組的餘量
8. 報文3的重傳定時器到期,沒有收到ACK,進行重傳
9. 這個時候Client已經收到報文4,存放在緩衝區中,也不會發送ACK【累計通知,傳送ACK就表示3也收到了】
10. Server收到確認之後,將報文3,4移除視窗,所有資料傳送完成
這種方式會面臨一個問題:客戶端在等待報文3的時候,伺服器如何處理報文4, 客戶端這個期間內並沒有傳送任何報文,伺服器並不知道報文3和報文4的狀態,報文4可能會丟失,也可能會被客戶端接收,那麼如果超時了,我到底值該傳送報文3 ,還是報文3和報文4 呢?
總結起來就是2中處理
1. 定時器溢位,重傳3
2. 定時器溢位,重傳3,4
對於重傳時間是如何計算的問題,在RFC2988中也提供了一種至今Linux使用的方案,詳細介紹可以參考文章:TCP-IP詳解 RTT and RTO
對於定時器溢位的問題,就來介紹一下 快速重傳機制。
快速重傳機制
在超時重傳中,重點是定時器溢位超時了才認為傳送的資料包丟失,快速重傳機制,實現了另外的一種丟包評定標準,即如果我連續收到3次dup ACK,傳送方就認為這個seq的包丟失了,立刻進行重傳,這樣如果接收端回覆及時的話,基本就是在重傳定時器到期之前,提高了重傳的效率。
在傳輸過程中會出現out-of-order的現象,但是在滑動視窗中會有嚴格的順序控制,假設有4,5,6三個待接收的資料包,先收到了5,6,協議棧是不會回覆對5,6包的確認,而是根據TCP協議的規定,當接收方收到亂序片段時,需要重複傳送ACK, 在這個地方會發送報文4 seq的ACK,表明需要報文4沒有被接收到,如果此後收到的是報文7,那麼仍然要回報文4 seq的ACK,如果連續傳送3個 dup ACK,接收端認為這個片段已經丟失,進行快速重傳。
看一個簡單的例子:這是下載過程中網路不好抓的tcpdump
1. 145/153/170 是3個dup ACK
2. 171包,快速重傳
不過快速重傳能夠解決超時的問題,但是對於之前討論的究竟重傳哪些包的問題,依然不能有效的解決,這就需要TCP中提供的SACK機制來解決。