TCP/IP協議--TCP的超時和重傳

  TCP是可靠傳輸。可靠之一體如今收到數據後,返回去一個確認。可是不能徹底避免的是,數據和確認均可能丟失。解決這個辦法就是,提供一個發送的重傳定時器:若是定時器溢出時還沒收到確認,它就重傳這個報文段。算法

想法是完美的,關鍵之處在於超時和重傳的策略,即怎麼決定超時間隔和如何肯定重傳的頻率。緩存

書中舉了一個簡單的超時重傳例子:網絡

如圖:tcp

好比A往B傳,傳了一部分數據後,把B的網線拔了(前邊講過,若是不傳數據的話,雙方無法知道這個鏈接已經斷了)。而後開始A再給B發數據,此時tcpdump出來發現,連續重傳了一個報文段:時間間隔分別是,1.013s, 3, 6, 12, 24 和多個64s...最後發了個復位報文段表示我放棄了。。(從第一次開始發這個報文段,到最後發一個復位段的時間差大約是9分鐘,這個9分鐘通常在TCP實現中是不變的)。性能

往返時間測量:
TCP的超時時間很大程度上是依賴報文段的往返時間。所以測量往返時間顯得尤其重要。
由於鏈路上的網絡流量或者路由器等的存在,往返時間通常不會是一成不變的,可能會常常發生變化。
最初的TCP規範這樣協議:RTT(Round-Trip Time)表示往返時間,用M表示測量到的RTT。
更新過的RTT = 0.9*RTT + 0.1*M 表示,我估計新的往返時間將是,0.9倍的以前的RTT + 0.1倍的新測量的RTT。(0.9叫平滑因子)
獲得了新的估計RTT,推薦的重傳超時時間RTO(Retransmission TimeOut)的值應該設置爲
RTO = RTT*b (這裏的b是一個推薦值爲2的時延離散因子)。超時時間就是大約2倍的往返時間。spa

以上這個計算超時時間的方法存在缺陷,[Jacobson 1988] 做出了詳細分析,當RTT變化範圍比較大的時候,這個方法顯得力不從心了,可能會引發沒必要要的重傳。這樣當網絡負載比較高的時候,再重傳會火上澆油...
     這就又有了新的方法計算重傳超時時間:
前邊說到若是RTT變化範圍較大時,容易發生沒必要要重傳。學過數學的都會知道,方差能夠體現出波動大小。這個方法就是用到了方差來均衡下。
這裏有個公式用來計算RTO,懂的原理就行了,這個計算RTO的公式依賴於估計的RTT和均值誤差(逼近與標準差),而最初的方法則使用了被平滑的RTT的一個倍數(b=2)。這塊知道是這麼個事就好~blog

 

往返時間RTT的測量:
如圖:排序

左邊的時間軸上有三個括號,它們代表爲進行RTT計算對哪些個報文段進行了計時,並非全部的報文段都被計時。在發送一個報文段時,若是給定鏈接的重傳定時器已經被使用,則該報文段不被計時。如圖報文段4或者報文段7都沒有參與計時。
對每一個鏈接而言,除了這個滴答計數器,報文段中數據的起始序號也被記錄下來。當收到一個包含這個序號的確認後,該定時器就被關閉。若是ACK到達時數據沒有被重傳,則被平滑的RTT和被平滑的均值誤差將基於這個新測量進行更新。進程

在每次調用500 ms的TCP的定時器例程時,就增長一個計數器來完成計時。這意味着,若是一個報文段的確認在它發送550 ms後到達,則該報文段的往返時間RTT將是1個滴答(即500 ms)或是2個滴答(即1000 ms)。
如圖RTT測量和時鐘滴答:ip

 

  -擁塞舉例:
主機slip老是通告窗口大小爲4096,而主機vangogh則通告窗口爲8192。
如圖:


報文段45丟失了,報文段58是正常接收43的報文段給出的確認,而後接着接收主機連續發了8個ack 6657。能夠看出是重發第三次(除了正常確認的中第3個)時,發送主機重傳發送了63報文段。
這收到第三個ack才重傳也是算法中要求的,當收到第3個時,就假定一個報文段已經丟失並重傳自那個序號起的一個報文段。這就是Jacobson的快速重傳算法
值得注意的是,在重傳後(報文段63),發送方繼續正常的數據傳輸(報文段6七、69和71)。TCP不須要等待對方確認重傳。

這裏再分析一下接收端是怎麼處理的: 當按序收到正常數據(報文段43)後,接收TCP將255個字節的數據交給用戶進程。但下一個收到的報文段(報文段46)是失序的(數據的開始序號 6913 並非下一個指望的序號 6657)。TCP保存256字節的數據,並返回一個已成功接收數據的最大序號加1(6657)的ACK。被vangogh接收到的後面7個報文段(48, 50, 52, 54, 55, 57和59)也是失序的,接收方TCP保存這些數據併產生重複ACK(TCP實現無法告訴對方,我就缺某某個報文段,它只能告訴發送方個人確認序號一直是這個)。
當缺乏的報文段(報文段 63)到達時,接收方TCP在其接收緩存中組合好第6657~8960字節的數據,並將這2304字節的數據交給用戶進程。全部這些數據在報文段72中進行確認。
值得注意的是,此時該ACK通告窗口大小爲5888(8192-2304,原來的通告窗口大小是8192),這是由於用戶進程此時尚未讀取出這些緩存中的字節。

 

  -擁塞避免:
該算法假定因爲分組受到損壞引發的丟失是很是少的(遠小於1%),所以分組丟失就意味着在源主機和目的主機之間的某處網絡上發生了擁塞。
有兩種分組丟失的指示:發生超時和接收到重複的確認(若是使用超時做爲擁塞指示,則須要使用一個好的RTT算法)。
前邊講過慢啓動,擁塞避免算法和慢啓動算法是兩個目的不一樣、獨立的算法。可是當擁塞發生時,咱們但願下降分組進入網絡的傳輸速率,因而能夠調用慢啓動來做到這一點。在實際中這兩個算法一般在一塊兒實現。

  -快速重傳和快速恢復算法:
在前邊擁塞舉例時,觀察到第三個ack過來,發送端才進行重傳。這是由於:因爲咱們不知道一個重複的ACK是由一個丟失的報文段引發的,仍是因爲僅僅出現了幾個報文段的從新排序,所以咱們等待少許重複的ACK到來。假如這只是一些報文段的從新排序,則在從新排序的報文段被處理併產生一個新的ACK以前,只可能產生1 ~ 2個重複的ACK。 若是一連串收到3個或3個以上的重複ACK,就很是多是一個報文段丟失了。因而咱們就重傳丟失的數據報文段,而無需等待超時定時器溢出。這就是快速重傳算法。
接下來收到重傳的ACK之前,發送了3個新的數據的報文段(報文段67,69和71)。執行的不是慢啓動算法而是擁塞避免算法。這就是快速恢復算法。在這種狀況下沒有執行慢啓動的緣由是因爲收到重複的ACK不只僅告訴咱們一個分組丟失了,而是在收發兩端之間仍然有流動的數據(因爲接收方只有在收到另外一個報文段時纔會產生重複的ACK,而該報文段已經離開了網絡並進入了接收方的緩存),所以咱們不想執行慢啓動來忽然減小數據流。

 

從新分組:
當TCP超時並重傳時,它不必定要重傳一樣的報文段。而是TCP容許進行從新分組而發送一個較大的報文段,這將有助於提升性能(固然,這個較大的報文段不可以超過接收方聲明的MSS)。
如圖:

第3個發送前,斷開網線。開始發送3,此時發生了重傳,在放棄鏈接前,又鍵入了幾個字節。而後插上網線,發現第8行,是把前邊兩次的分組組裝成了一個分組發過去的。

 

TCP的超時重傳...end

-

相關文章
相關標籤/搜索