TCP協議的那些超時


 

 

眾所周知,TCP協議是一個 可靠的 的協議。TCP的可靠性依賴於大量的 Timer 和 Retransmission 。現在咱們就來細說一下TCP協議的那些 Timer 。

TCP State transition diagram

1. Connection-Establishment Timer

在TCP三次握手創建一個連接時,以下兩種情況會發生超時:

  1. client發送SYN后,進入SYN_SENT狀態,等待server的SYN+ACK。
  2. server收到連接創建的SYN,回應SYN+ACK后,進入SYN_RECD狀態,等待client的ACK。

當超時發生時,就會重傳,一直到75s還沒有收到任何回應,便會放棄,終止連接的創建。但是在Linux實現中,並不是依靠超時總時間來判斷是否終止連接。而是依賴重傳次數:

  • tcp_syn_retries (integer; default: 5; since Linux 2.2)

    The maximum number of times initial SYNs for an active TCP connection attempt will be retransmitted. This value should not be higher than 255. The default value is 5, which corresponds to approximately 180 seconds.

  • tcp_synack_retries (integer; default: 5; since Linux 2.2)

    The maximum number of times a SYN/ACK segment for a passive TCP connection will be retransmitted. This number should not be higher than 255.

2. Retransmission Timer

當三次握手成功,連接建立,發送TCP segment,等待ACK確認。如果在指定時間內,沒有得到ACK,就會重傳,一直重傳到放棄為止。Linux中也有相關變量來設置這里的重傳次數的:

  • tcp_retries1 (integer; default: 3; since Linux 2.2)

    The number of times TCP will attempt to retransmit a packet on an established connection normally, without the extra effort of getting the network layers involved. Once we exceed this number of retransmits, we first have the network layer update the route if possible before each new retransmit. The default is the RFC specified minimum of 3.

  • tcp_retries2 (integer; default: 15; since Linux 2.2)

    The maximum number of times a TCP packet is retransmitted in established state before giving up. The default value is 15, which corresponds to a duration of approxi‐mately between 13 to 30 minutes, depending on the retransmission timeout. The RFC 1122 specified minimum limit of 100 seconds is typically deemed too short.

3. Delayed ACK Timer

當一方接受到TCP segment,需要回應ACK。但是不需要 立即 發送,而是等上一段時間,看看是否有其他數據可以 捎帶 一起發送。這段時間便是 Delayed ACK Timer ,一般為200ms。

4. Persist Timer

如果某一時刻,一方發現自己的 socket read buffer 滿了,無法接受更多的TCP data,此時就是在接下來的發送包中指定通告窗口的大小為0,這樣對方就不能接着發送TCP data了。如果socket read buffer有了空間,可以重設通告窗口的大小在接下來的 TCP segment 中告知對方。可是萬一這個 TCP segment 不附帶任何data,所以即使這個segment丟失也不會知曉(ACKs are not acknowledged, only data is acknowledged)。對方沒有接受到,便不知通告窗口的大小發生了變化,也不會發送TCP data。這樣雙方便會一直僵持下去。

TCP協議采用這個機制避免這種問題:對方即使知道當前不能發送TCP data,當有data發送時,過一段時間后,也應該嘗試發送一個字節。這段時間便是 Persist Timer 。

5. Keepalive Timer

TCP socket 的 SO_KEEPALIVE option,主要適用於這種場景:連接的雙方一般情況下沒有數據要發送,僅僅就想嘗試確認對方是否依然在線。目前vipbar網吧,判斷當前客戶端是否依然在線,就用的是這個option。

具體實現方法:TCP每隔一段時間(tcp_keepalive_intvl)會發送一個特殊的 Probe Segment,強制對方回應,如果沒有在指定的時間內回應,便會重傳,一直到重傳次數達到 tcp_keepalive_probes 便認為對方已經crash了。

  • tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)

    The number of seconds between TCP keep-alive probes.

  • tcp_keepalive_probes (integer; default: 9; since Linux 2.2)

    The maximum number of TCP keep-alive probes to send before giving up and killing the connection if no response is obtained from the other end.

  • tcp_keepalive_time (integer; default: 7200; since Linux 2.2)

    The number of seconds a connection needs to be idle before TCP begins sending out keep-alive probes. Keep-alives are only sent when the SO_KEEPALIVE socket option is enabled. The default value is 7200 seconds (2 hours). An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval of 75 sec‐onds apart) when keep-alive is enabled.

Note that underlying connection tracking mechanisms and application timeouts may be much shorter.

6. FIN_WAIT_2 Timer

當主動關閉方想關閉TCP connection,發送FIN並且得到相應ACK,從FIN_WAIT_1狀態進入FIN_WAIT_2狀態,此時不能發送任何data了,只等待對方發送FIN。可以萬一對方一直不發送FIN呢?這樣連接就一直處於FIN_WAIT_2狀態,也是很經典的一個DoS。因此需要一個Timer,超過這個時間,就放棄這個TCP connection了。

  • tcp_fin_timeout (integer; default: 60; since Linux 2.2)

    This specifies how many seconds to wait for a final FIN packet before the socket is forcibly closed. This is strictly a violation of the TCP specification, but required to prevent denial-of-service attacks. In Linux 2.2, the default value was 180.

7. TIME_WAIT Timer

TIME_WAIT Timer存在的原因和必要性,主要是兩個方面:

  1. 主動關閉方發送了一個ACK給對方,假如這個ACK發送失敗,並導致對方重發FIN信息,那么這時候就需要TIME_WAIT狀態來維護這次連接,因為假如沒有TIME_WAIT,當重傳的FIN到達時,TCP連接的信息已經不存在,所以就會重新啟動消息應答,會導致對方進入錯誤的狀態而不是正常的終止狀態。假如主動關閉方這時候處於TIME_WAIT,那么仍有記錄這次連接的信息,就可以正確響應對方重發的FIN了。
  2. 一個數據報在發送途中或者響應過程中有可能成為殘余的數據報,因此必須等待足夠長的時間避免新的連接會收到先前連接的殘余數據報,而造成狀態錯誤。

但是我至今疑惑的是:為什么這個超時時間的值為2MSL?如果為了保證雙方向的TCP包要么全部響應完畢,要么全部丟棄不對新連接造成干擾,這個時間應該是:

被動關閉方LAST_ACK的超時時間 + 1MSL

因為被動關閉方進入LAST_ACK狀態后,假設一直沒有收到最后一個ACK,會一直重傳FIN,一直重傳次數到達TCP_RETRIES放棄,將這個時間定義為「被動關閉方LAST_ACK的超時時間」,接着必須等待最后一個重傳的FIN失效,需要一個MSL的時間。這樣才能保證所有重傳的FIN包失效,不干擾新連接吧。


免責聲明!

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



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