1. 程式人生 > >TCP超時與重傳機制

TCP超時與重傳機制

ont bsp 想是 假設 我們 情況下 服務器端 事情 客戶

TCP超時與重傳機制
  
  TCP協議是一種面向連接的可靠的傳輸層協議,它保證了數據的可靠傳輸,對於一些出錯,超時丟包等問題TCP設計的超時與重傳機制。其基本原理:在發送一個數據之後,就開啟一個定時器,若是在這個時間內沒有收到發送數據的ACK確認報文,則對該報文進行重傳,在達到一定次數還沒有成功時放棄並發送一個復位信號。
  這裏比較重要的是重傳超時時間,怎樣設置這個定時器的時間(RTO),從而保證對網絡資源最小的浪費。因為若RTO太小,可能有些報文只是遇到擁堵或網絡不好延遲較大而已,這樣就會造成不必要的重傳。太大的話,使發送端需要等待過長的時間才能發現數據丟失,影響網絡傳輸效率。
  由於不同的網絡情況不一樣,不可能設置一樣的RTO,實際中RTO是根據網絡中的RTT(傳輸往返時間)來自適應調整的。具體關系參考相關算法。

  通過圖來了解重傳機制:

技術分享圖片

從圖可以知道,發送方連續發送3個數據包,其中第二個丟失,沒有被接收到,因此不會返回對應的ACK,沒發送一個數據包,就啟動一個定時器,當第二個包的定時器溢出了還沒有收到ack,這時就進行重傳。

TCP慢啟動

  慢啟動是TCP的一個擁塞控制機制,慢啟動算法的基本思想是當TCP開始在一個網絡中傳輸數據或發現數據丟失並開始重發時,首先慢慢的對網路實際容量進行試探,避免由於發送了過量的數據而導致阻塞。
  慢啟動為發送方的TCP增加了另一個窗口:擁塞窗口(congestion window),記為cwnd。當與另一個網絡的主機建立TCP連接時,擁塞窗口被初始化為 1個報文段(即另一端通告的報文段大小)。每收到一個ACK,擁塞窗口就增加一個報文段(cwnd以字節為單位,但是慢啟動以報文段大小為單位進行增加)。發送方取擁塞窗口與通告窗口中的最小值作為發送上限。擁塞窗口是發送方使用的流量控制,而通告窗口則是接收方使用的流量控制。發送方開始時發送一個報文段,然後等待 ACK。當收到該ACK時,擁塞窗口從1增加為2,即可以發送兩個報文段。當收到這兩個報文段的 A C K時,擁塞窗口就增加為4。這是一種指數增加的關系。

擁塞避免算法

  網絡中擁塞的發生會導致數據分組丟失,需要盡量避免。在實際中,擁塞算法與慢啟動通常在一起實現,其基本過程:
   1. 對一個給定的連接,初始化cwnd為1個報文段,ssthresh為65535個字節。
   2. TCP輸出例程的輸出不能超過cwnd和接收方通告窗口的大小。擁塞避免是發送方使用 的流量控制,而通告窗口則是接收方進行的流量控制。前者是發送方感受到的網絡擁塞的估 計,而後者則與接收方在該連接上的可用緩存大小有關。
   3. 當擁塞發生時(超時或收到重復確認),ssthresh被設置為當前窗口大小的一半(cwnd 和接收方通告窗口大小的最小值,但最少為2個報文段)。此外,如果是超時引起了擁塞,則 cwnd被設置為1個報文段(這就是慢啟動)。

   4. 當新的數據被對方確認時,就增加cwnd,但增加的方法依賴於是否正在進行慢啟動或擁塞避免。如果cwnd小於或等於ssthresh,則正 在進行慢啟動,否則正在進行擁塞避免。慢啟動一直持續到回到當擁塞發生時所處位置的半時候才停止(因為記錄了在步驟2 中制造麻煩的窗口大小的一半),然後轉為執行擁塞避免。
   慢啟動算法初始設置cwnd為1個報文段,此後每收到一個確認就加 1。那樣,這會使窗口按指數方式增長:發送 1個報文段,然後是2個,接著是4個……。

技術分享圖片

在該圖中,假定當cwnd為32個報文段時就會發生擁塞。於是設置 ssthresh為16個報文段,而cwnd為1個報文段。在時刻 0發送了一個報文段,並假定在時刻 1接收到它的ACK,此時cwnd增加為2。接著發送了2個報文段,並假定在時刻 2接收到它們的ACK,於是cwnd增加為4(對每個ACK增加1次)。這種指數增加算法一直進行到在時刻3和4之間收到8個ACK後cwnd等於ssthresh時才停止,從該時刻起,cwnd以線性方式增加,在每個往返時間內最多增加 1個報文段。

  什麽是計時器呢?我們可以理解成一塊鬧鐘,隔一段時間響一次,提醒TCP做特定的事情。TCP要正常工作,必須要有特定的計時器。那麽TCP中有哪些計時器呢?

  TCP中有四種計時器(Timer),分別為:

    1.重傳計時器:Retransmission Timer

    2.堅持計時器:Persistent Timer

    3.保活計時器:Keeplive Timer

    4.時間等待計時器:Timer_Wait Timer

  (1)重傳計時器

    大家都知道TCP是保證數據可靠傳輸的。怎麽保證呢?帶確認的重傳機制。在滑動窗口協議中,接受窗口會在連續收到的包序列中的最後一個包向接收端發送一個ACK,當網絡擁堵的時候,發送端的數據包和接收端的ACK包都有可能丟失。TCP為了保證數據可靠傳輸,就規定在重傳的“時間片”到了以後,如果還沒有收到對方的ACK,就重發此包,以避免陷入無限等待中。

  當TCP發送報文段時,就創建該特定報文的重傳計時器。可能發生兩種情況:

  1.若在計時器截止時間到之前收到了對此特定報文段的確認,則撤銷此計時器。

  2.若在收到了對此特定報文段的確認之前計時器截止時間到,則重傳此報文段,並將計時器復位。

  (2)持久計時器

  先來考慮一下情景:發送端向接收端發送數據包知道接受窗口填滿了,然後接受窗口告訴發送方接受窗口填滿了停止發送數據。此時的狀態稱為“零窗口”狀態,發送端和接收端窗口大小均為0.直到接受TCP發送確認並宣布一個非零的窗口大小。但這個確認會丟失。我們知道TCP中,對確認是不需要發送確認的。若確認丟失了,接受TCP並不知道,而是會認為他已經完成了任務,並等待著發送TCP接著會發送更多的報文段。但發送TCP由於沒有收到確認,就等待對方發送確認來通知窗口大小。雙方的TCP都在永遠的等待著對方。

  要打開這種死鎖,TCP為每一個鏈接使用一個持久計時器。當發送TCP收到窗口大小為0的確認時,就堅持啟動計時器。當堅持計時器期限到時,發送TCP就發送一個特殊的報文段,叫做探測報文。這個報文段只有一個字節的數據。他有一個序號,但他的序號永遠不需要確認;甚至在計算機對其他部分的數據的確認時該序號也被忽略。探測報文段提醒接受TCP:確認已丟失,必須重傳。

  堅持計時器的值設置為重傳時間的數值。但是,若沒有收到從接收端來的響應,則需發送另一個探測報文段,並將堅持計時器的值加倍和復位。發送端繼續發送探測報文段,將堅持計時器設定的值加倍和復位,直到這個值增大到門限值(通常是60秒)為止。在這以後,發送端每個60秒就發送一個探測報文,直到窗口重新打開。

  (3)保活計時器

    保活計時器使用在某些實現中,用來防止在兩個TCP之間的連接出現長時間的空閑。假定客戶打開了到服務器的連接,傳送了一些數據,然後就保持靜默了。也許這個客戶出故障了。在這種情況下,這個連接將永遠的處理打開狀態。

  要解決這種問題,在大多數的實現中都是使服務器設置保活計時器。每當服務器收到客戶的信息,就將計時器復位。通常設置為兩小時。若服務器過了兩小時還沒有收到客戶的信息,他就發送探測報文段。若發送了10個探測報文段(每一個像個75秒)還沒有響應,就假定客戶除了故障,因而就終止了該連接。

  這種連接的斷開當然不會使用四次握手,而是直接硬性的中斷和客戶端的TCP連接。

  (4)時間等待計時器

  時間等待計時器是在四次握手的時候使用的。四次握手的簡單過程是這樣的:假設客戶端準備中斷連接,首先向服務器端發送一個FIN的請求關閉包(FIN=final),然後由established過渡到FIN-WAIT1狀態。服務器收到FIN包以後會發送一個ACK,然後自己有established進入CLOSE-WAIT.此時通信進入半雙工狀態,即留給服務器一個機會將剩余數據傳遞給客戶端,傳遞完後服務器發送一個FIN+ACK的包,表示我已經發送完數據可以斷開連接了,就這便進入LAST_ACK階段。客戶端收到以後,發送一個ACK表示收到並同意請求,接著由FIN-WAIT2進入TIME-WAIT階段。服務器收到ACK,結束連接。此時(即客戶端發送完ACK包之後),客戶端還要等待2MSL(MSL=maxinum segment lifetime最長報文生存時間,2MSL就是兩倍的MSL)才能真正的關閉連接。

技術分享圖片

TCP超時與重傳機制