TCP系列12—重傳—2、Linux超時重傳引入示例


        在前面我們概述了TCP的超時重傳之后我們簡單的看一下tcp超時重傳的示例。首先簡單的描述一下測試過程

1、設置/proc/sys/net/ipv4/tcp_early_retrans為2,關掉TLP功能(后面內容介紹TLP)。設置/proc/sys/net/ipv4/tcp_retries2為8,減少重傳次數,這樣方便wireshark抓包演示。同時設置/proc/sys/net/ipv4/tcp_discard_on_port為9877,以讓client可以精確的控制發出的TCP報文,而不受到內核TCP模塊的影響。

2、client通過raw socket直接在IP層之上構造TCP報文,與server通過三次握手建立連接,其中client為127.0.0.1:10000,server為127.0.0.1:9877。這個步驟對應No1--No3報文。

3、TCP連接建立后client發送"hello"消息給服務器,服務器則回復ACK,這個步驟對應No4--No5報文。

4、server發送“hello”給client,這個步驟對應No6報文。

5、client收到server的"hello"報文后,直接丟棄並不回復ACK。

6、server在沒有收到ACK報文的情況下,過了大約1.5s后,server端RTO超時,觸發超時重傳。client同樣在收到這些重傳報文的時候直接丟棄而不回復ACK,這樣server持續重傳。一共重傳了6次。

這個過程的wireshark截圖如下(為了方便觀察RTO,我把No6初傳設置為時間參考點,后面數據包的Time時間都是相對於No6包的時間):

從這個超時重傳示例中我們重點關注幾個方面

1、可以看到No7第一次重傳與No6初傳間隔大約為1.5s,No8第二次重傳與No7時間間隔大約是3.0s,No9第三次重傳與No8時間間隔大約是6.0s。可以看到每次重傳后,重傳的時間間隔(即RTO)都是上次重傳時間間隔的2倍。實際我們從server端程序可以獲取到Linux內核中TCP模塊計算的RTO分別為1.504s、3.008s、6.016s。也可以精確的看到RTO的倍增關系。這種RTO倍增關系就是指數回退(binary exponential backoff)

2、我們在測試過程描述中說明設置tcp_retries2為8,而從wireshark中可以看到實際只是發生了6次重傳。實際上linux內核會根據tcp_retries2計算出一個timeout,計算方式如下面代碼所示,其中對於established狀態下的endpoint,rto_base為200ms,TCP_RTO_MAX為120000ms。當tcp_retries2設置為8的時候,按照下面流程計算得出timeout=102.2s。其中No11和No12之間的RTO為48s左右(根據server端實際獲取的信息,linux內部實際計算出的RTO為48.128s),如果進一步指數回退,則下一次重傳時間點大約是48*2+94=190s,可以看到190s已經超過了計算出的timeout(即102.2s)值,應該不會進一步進行重傳,多次超時重傳失敗server端則會直接釋放這個tcp連接,釋放這個連接后如果server端嘗試進一步寫入數據就會返回ETIMEDOUT的錯誤

 
 
 
         
  1. if (tcp_retries2 <= 9)
  2. timeout = ((2 << tcp_retries2) - 1) * rto_base;
  3. else
  4. timeout = ((2 << 9) - 1) * rto_base +
  5. (tcp_retries2 - 9) * TCP_RTO_MAX;

在RFC1122中有兩個門限R1和R2,當重傳次數超過R1的時候,TCP向IP層發送negative advice,指示IP層進行MTU探測、刷新路由等過程,以防止由於網絡鏈路發生變化而導致TCP傳輸失敗。當重傳次數超過R2的時候,TCP放棄重傳並關閉TCP連接。其中R1和R2也可以表述為時間,即總重傳時間超過R1或者R2的時候觸發響應的操作。在linux中對於普通數據報文狀態下的TCP,R1對應/proc/sys/net/ipv4/tcp_retries1,R2對應/proc/sys/net/ipv4/tcp_retries2參數。這兩個參數都是根據上面的計算流程計算出一個timeout值,當總重傳時間超過這個timeout值還沒有收到ack的時候觸發響應的操作。對於SYN報文如我們之前所講,則是由tcp_syn_retries和tcp_synack_retries這兩個參數控制


補充說明:

1、linux中根據tcp_retries1和tcp_retries2計算timeout的過程參考代碼retransmits_timed_out。

2、網上很多資料以及man 7 tcp和第二版的tcpip詳解中對於tcp_retries1或tcp_retries2描述都是按照重傳次數來描述的,實際上是錯誤的。









免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM