本博客參考自《TCP/IP詳解卷一:協議》
本文主要介紹TCP中的超時重傳
1.往返時間RTT的計算
TCP提供可靠的運輸層,其中重要的方法之一就是確認從另一端收到的數據。但數據和確認都有可能丟失。TCP通過在發送時設置一個定時器來解決這個問題。如果定時器溢出時還沒有收到確認,就重傳數據。
TCP超時和重傳中最重要的部分是對一個給定連接的往返時間(RTT)的測量。在網絡傳輸的過程中,這個值經常是變化的。RTT的測量必須是在同一報文的發送和確認之間。
較早的時候是通過低通濾波器來更新一個被平滑的RTT估計器來計算超時重傳時間RTO(retransmission timeout)。用M表示測量的RTT,R表示被平滑的RTT估計值。
這裏的一般取值0.9,一般取值2。這種方法在RTT的變化範圍很大的時候,無法跟上變化,從而引起不必要的重傳。所以提出了一種新的方法。除了被平滑的RTT估計器,還需要根據RTT的方差。這種計算方法在往返時間起伏很大的時候可以得到一個較好的響應。
這裏A是被平滑的RTT而D是被平滑的均值偏差。Err是剛得到的測量結果與之前的RTT估計器之差。增量g起平均作用,一般取值0.125。h是偏差的增益,一般取0.25。當RTT增大時,較大的偏差增益將使RTO快速上升。
1.1 Karn算法
在一個分組重傳時會產生這樣一個問題:假定一個分組被髮送。當超時發生時, RTO會進行退避(增長),分組以更長的RTO進行重傳,然後收到一個確認。這個確認是針對第一個或第二個分組,難以確認。這就導致重傳的二義性。
Karn算法規定,當一個超時和重傳發生時,在重傳數據的確認最後達到之前,不能更行RTT估計器。
1.2 RTT計算舉例
在這個例子中,客戶端一共向服務器發送了32678字節的數據,這裏只截取了一部分。
從上圖中可以看出,RTT的更新只在同一報文的確認到達時才啓動。TCP中內置了一個500ms的定時器,沒發送一次數據時,這個定時器都會啓動。在報文4時,該定時器已經在啓動的狀態,所以不會對報文段4進行計時,同理7,9報文段。
注意這個定時器同我們理解的定時器不同,它記錄的是時鐘的滴答,即只要時鐘經過一個滴答定時器就加1,記錄一個500ms。舉例來說,在系統時鐘某一滴答後的490ms,你啓動了定時器。10ms後系統時鐘經歷一次滴答,你的定時器就會定時500ms,雖然此時真實的時間只有10ms。
上圖顯示了實際的RTT同系統時鐘的滴答之間的關係,圖中虛線表示系統時鐘的滴答時刻。可以看出,RTT #1經歷的時鐘滴答爲3,RTT #2經歷的時鐘滴答爲1,RTT #3經歷的時鐘滴答爲2。
下面根據RTT對RTO的值進行估計計算
①初始化A和D分別爲0和3
因子2D只在初始化的時候出現,後面的計算都會以4D代替。
②同步報文超時重傳,RTO指數退避
③確認報文2到達
由於估計值A一開始的值爲0,所以估計器A需要被初始化。此時RTT爲3個時鐘滴答,所以M的值爲1.5
③確認報文5到達,RTT爲1個時鐘滴答,M的值爲0.5
④報文段10到達,RTT爲2個時鐘滴答,M的值爲1
下圖是測量的RTT和RTO的曲線
上表是確認報文2到達開始計算的。
2.擁塞避免算法
網絡通信有時會達到中間路由器的極限,分組會丟失。擁塞避免是處理這種丟失分組的方法。該方法假設,分組丟失是由源主機和目的主機之間的某處網絡故障造成的。有兩種情況表示分組丟失:發生超時和接收到重複確認。
當擁塞發生時,爲了降低分組進入網絡的傳輸速率,需要調用慢啓動算法來實現。擁塞避免和慢啓動算法需要對每個連接維持兩個變量一個擁塞窗口和一個慢啓動門限。這樣得到的算法的工作過程如下:
1) 對一個給定的連接,初始化爲1個報文段,爲6 5 5 3 5個字節。
2) TCP輸出例程的輸出不能超過和接收方通告窗口的大小。擁塞避免是發送方使用的流量控制,而通告窗口則是接收方進行的流量控制。前者是發送方感受到的網絡擁塞的估計,而後者則與接收方在該連接上的可用緩存大小有關。
3) 當擁塞發生時(超時或收到重複確認),被設置爲當前窗口大小的一半()和接收方通告窗口大小的最小值,但最少爲 2個報文段)。此外,如果是超時引起了擁塞,則被設置爲1個報文段(這就是慢啓動)。
4) 當新的數據被對方確認時,就增加,但增加的方法依賴於我們是否正在進行慢啓動或擁塞避免。如果小於或等於,則正在進行慢啓動,否則正在進行擁塞避免。慢啓動一直持續到我們回到當擁塞發生時所處位置的半時候才停止(因爲記錄了在步驟 2中給我們製造麻煩的窗口大小的一半),然後轉爲執行擁塞避免。
擁塞避免算法要求每次收到一個確認時將增加爲。這樣就保證理想情況下每個往返時間增加一個窗口大小。這是一種線性增長。下圖展示了慢啓動和擁塞避免算法的工作流程。
當=32時發送擁塞,接着,,這時執行慢啓動算法。當時,慢啓動算法失效,每個RTT內只增加一個。
3.快速重傳和快速恢復算法
TCP的連接中,當收到3個以上的重複ACK,就認爲是報文段的丟失。接下來就會重傳數據報文段,無需等待超時定時器溢出。這就是快速重傳算法。快速重傳算法首先執行擁塞避免算法,而不是慢啓動,這就是說不會變爲1。算法的具體流程如下:
1) 當收到第3個重複的ACK時,將設置爲當前擁塞窗口的一半。重傳丟失的報文段。設置爲加上3倍的報文段大小。
2) 每次收到另一個重複的ACK時,增加1個報文段大小併發送 1個分組(如果新的允許發送)。
3) 當下一個確認新數據的A C K到達時,設置爲(在第1步中設置的值)。這個ACK應該是在進行重傳後的一個往返時間內對步驟 1中重傳的確認。另外,這個ACK也應該是對丟失的分組和收到的第 1個重複的ACK之間的所有中間報文段的確認。這一步採用的是擁塞避免,因爲當分組丟失時將當前的速率減半。