1. 程式人生 > >TCP中的7種定時器詳解

TCP中的7種定時器詳解

TCP中的7種定時器:

  1. 建立連線定時器(connection-establishment timer)
  2. 重傳定時器(retransmission timer)
  3. 延遲應答定時器(delayed ACK timer)
  4. 堅持定時器(persist timer)
  5. 保活定時器(keepalive timer)
  6. FIN_WAIT_2定時器(FIN_WAIT_2 timer)
  7. TIME_WAIT定時器 (TIME_WAIT timer, 也叫2MSL timer)

下面分別介紹一下這幾種定時器:

建立連線定時器(connection-establishment timer)

   顧名思義,這個定時器是在建立連線的時候使用的, 我們知道, TCP建立連線需要3次握手, 如下圖所示:
這裡寫圖片描述


   建立連線的過程中,在傳送SYN時, 會啟動一個定時器(預設應該是3秒),如果SYN包丟失了, 那麼3秒以後會重新發送SYN包的(當然還會啟動一個新的定時器, 設定成6秒超時),當然也不會一直沒完沒了的發SYN包, 在/proc/sys/net/ipv4/tcp_syn_retries 可以設定到底要重新發送幾次SYN包。

重傳定時器(retransmission timer)

   重傳定時器在TCP傳送資料時設定,在計時器超時後沒有收到返回的確認ACK,傳送端就會重新發送佇列中需要重傳的報文段。使用RTO重傳計時器一般有如下規則:

  1. 當TCP傳送了位於傳送佇列最前端的報文段後就啟動這個RTO計時器;
  2. 如果佇列為空則停止計時器,否則重啟計時器;
  3. 當計時器超時後,TCP會重傳發送佇列最前端的報文段;
  4. 當一個或者多個報文段被累計確認後,這個或者這些報文段會被清除出佇列

   重傳計時器保證了接收端能夠接收到丟失的報文段,繼而保證了接收端交付給接收程序的資料始終的有序完整的。因為接收端永遠不會把一個失序不完整的報文段交付給接收程序。

延遲應答定時器(delayed ACK timer)

   延遲應答也被成為捎帶ACK, 這個定時器是在延遲應答的時候使用的。 為什麼要延遲應答呢? 延遲應答是為了提高網路傳輸的效率。

   舉例說明,比如服務端收到客戶端的資料後, 不是立刻回ACK給客戶端, 而是等一段時間(一般最大200ms),這樣如果服務端要是有資料需要發給客戶端,那麼這個ACK就和服務端的資料一起發給客戶端了, 這樣比立即回給客戶端一個ACK節省了一個數據包。

堅持定時器(persist timer)

   我們已經知道TCP通過讓接收方指明希望從傳送方接收的資料位元組數(即視窗大小)來進行流量控制。如果視窗大小為 0會發生什麼情況呢?這將有效地阻止傳送方傳送資料,直到視窗變為非0為止。接收端視窗變為非0後,就會發送一個確認ACK指明需要的報文段序號以及視窗大小。

   如果這個確認ACK丟失了,則雙方就有可能因為等待對方而使連線終止:接收方等待接收資料(因為它已經向傳送方通告了一個非0的視窗),而傳送方在等待允許它繼續傳送資料的視窗更新。為防止這種死鎖情況的發生,傳送方使用一個堅持定時器 (persist timer)來週期性地向接收方查詢,以便發現視窗是否已增大。這些從傳送方發出的報文段稱為視窗探查 (window probe)。

保活定時器(keepalive timer)

   在TCP連線建立的時候指定了SO_KEEPALIVE,保活定時器才會生效。如果客戶端和服務端長時間沒有資料互動,那麼需要保活定時器來判斷是否對端還活著,但是這個其實很不實用,因為預設是2小時沒有資料互動才探測,時間實在是太長了。如果你真的要確認對端是否活著, 那麼應該自己實現心跳包,而不是依賴於這個保活定時器。

FIN_WAIT_2定時器(FIN_WAIT_2 timer)

   主動關閉的一端呼叫完close以後(即發FIN給被動關閉的一端, 並且收到其對FIN的確認ACK)則進入FIN_WAIT_2狀態。如果這個時候因為網路突然斷掉、被動關閉的一段宕機等原因,導致主動關閉的一端不能收到被動關閉的一端發來的FIN,主動關閉的一段總不能一直傻等著,佔著資源不撒手吧?這個時候就需要FIN_WAIT_2定時器出馬了, 如果在該定時器超時的時候,還是沒收到被動關閉一端發來的FIN,那麼不好意思, 不等了, 直接釋放這個連結。FIN_WAIT_2定時器的時間可以從/proc/sys/net/ipv4/tcp_fin_timeout中檢視和設定。

TIME_WAIT定時器 (TIME_WAIT timer, 也叫2MSL timer)

   TIME_WAIT是主動關閉連線的一端最後進入的狀態, 而不是直接變成CLOSED的狀態, 為什麼呢?第一個原因是萬一被動關閉的一端在超時時間內沒有收到最後一個ACK, 則會重發最後的FIN,2MSL(報文段最大生存時間)等待時間保證了重發的FIN會被主動關閉的一段收到且重新發送最後一個ACK;另外一個原因是在2MSL等待時間時,任何遲到的報文段會被接收並丟棄,防止老的TCP連線的包在新的TCP連線裡面出現。不可避免的,在這個2MSL等待時間內,不會建立同樣(源IP, 源埠,目的IP,目的埠)的連線。

參考資料

《TCP/IP協議詳解》
《高效TCP/IP程式設計》