【網絡編程】TCP維護的七個定時器


TCP 是面向連接的,可靠的流式傳輸的傳輸層協議,它使用的方法之一就是·確認從另一端收到的數據【確認應答機制】。但是數據發送和確認都可能會丟失。TCP 通過在·發送時設置一個定時器·來解決這個問題。如果當定時器溢出時還沒收到確認,它就會重傳該數據。關鍵在於超時和重傳策略,即怎樣決定超時的時間間隔如何確定重傳的頻率。

1.建立連接定時器(connection-establishment timer)

顧名思義,這個定時器是在建立連接的時候使用的, 我們知道, TCP建立連接需要3次握手, 如下圖所示:
TCP三次握手
如果client在連接server的時候,在發送SYN的時候,會啓動一個定時器(默認應該是3秒),如果SYN包丟失(3秒收不到回覆)了,那麼3秒以後會重新發送SYN包的(當然還會啓動一個新的定時器,設置成6秒超時),當然也不會一直沒完沒了的發SYN包。在/proc/sys/net/ipv4/tcp_syn_retries 可以設置到底要重新發送幾次SYN包。(默認6次)
在這裏插入圖片描述
參考博客:關於TCP的syn丟失的事情

2.重傳定時器(retransmission timer)

對於TCP發送出去的數據包是先加載到內存,在發送出去, 需要等待對端發來ACK才能從內存裏面刪除, 那麼如果對端沒有發送ACK怎麼辦? 重傳唄, 在發送數據的同時,在設置一個超時時間(RTO),如果在這個超時時間內, 沒有收到ACK,那麼就重傳剛纔發送的數據。
·RTT(Round Trip Time):一個連接的往返時間,即數據發送時刻到接收到確認的時刻的差值;
RTO(Retransmission Time Out):重傳超時時間,即從數據發送時刻算起,超過這個時間便執行重傳。
RTT和RTO 的關係是:由於網絡波動的不確定性,每個RTT都是動態變化的,所以RTO也應隨着RTT動態變化。
重傳定時器在TCP發送數據時設定,在計時器超時後沒有收到返回的確認ACK,發送端就會重新發送隊列中需要重傳的報文段。使用RTO重傳計時器一般有如下規則:

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

重傳計時器保證了接收端能夠接收到丟失的報文段,繼而保證了接收端交付給接收進程的數據始終的有序完整的。因爲接收端永遠不會把一個失序不完整的報文段交付給接收進程。
參考博客:關於TCP的syn丟失的事情

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

顧名思義,這個定時器是在延遲應答的時候使用的。
爲什麼要延遲應答呢? 比如客戶端發一段數據給服務端,服務端本應該立刻回ACK給客戶端的,延遲應答是爲了提高網絡傳輸的效率,比如服務端收到客戶端的數據後,不是立刻回ACK給客戶端,而是等一段時間(一般最大200ms),這樣如果服務端要是有數據需要發給客戶端,那麼這個ACK就和服務端的數據一起發給客戶端了,這樣比立即回給客戶端一個ACK節省了一個數據包。

4.堅持定時器(persist timer)

堅持定時器是在收到receive window爲0的時候開始啓動的.
這裏寫圖片描述

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

計算堅持定時器時使用了普通的TCP指針退避窗口探查報文包含一個字節的數據。首次超時時間是1.5秒,之後的超時時間增加一倍,但總在5~60秒之間。
堅持狀態與重傳超時之間一個不同的特點就是TCP從不放棄發送窗口探查。這些探查每隔60秒發送一次,這個過程將持續到窗口打開或者應用進程使用的連接被終止。

附:糊塗窗口綜合症

糊塗窗口綜合症:接收方可以通告一個小的窗口(而不是一直等到有大的窗口時才通告),而發送方可以通過這個小窗口發送少量的數據(而不是等待其它的數據以便發送一個大的報文段),即,少量的數據通過連接交換,而不是滿長度的報文段,TCP的傳輸效率可想而知。

如何避免“糊塗窗口綜合症”:
接收方:接收方不通告小窗口,除非增加一個報文段(MMS)或者接收方緩存空間的一半,否則通告爲0。
發送方
(1)可以發送一個滿長度的報文段(MMS)
(2)可以發送至少接收方通告窗口一半的報文段
(3)能夠發送手頭的所有數據並且不希望接收ACK,或者該連接禁止了Nagle算法時,可以發送任意數據。
堅持定時器工作流程:

(1)發送端收到0窗口通告後,就啓動堅持定時器,並在定時器溢出的時候向客戶端查詢窗口是否已經增大。
(2)在定時器未到,就收到非零通告,則關閉該定時器,併發送數據。
(3)若定時器已到,還沒有收到非零通告,就發探查報文。
(4)如果探查報文ACK的通告窗口爲0,就將堅持定時器的值加倍,TCP的堅持定時器使用1,2,4,8,16……64秒這樣的普通指數退避序列來作爲每一次的溢出時間,重複1、2、3步,如果通告窗口非零,發送數據,關閉定時器。

5.保活定時器(keepalive timer)

現實中可能存在這麼一種空閒TCP連接:沒有任何數據流通過。也就是說,如果TCP連接的雙方都沒有向對方發送數據,則在兩個TCP模塊之間不交換任何信息,這意味着我們可以啓動一個客戶與服務器建立連接,然後長時間不使用,而連接依然保持中間的路由器可以崩潰和重啓,電話線可以被掛斷再連接,但只要兩端的主機沒有被重啓,則連接依然保持建立。
然而,許多時候一個服務器希望知道客戶主機是否崩潰並關機或者崩潰又重新啓動,許多實現提供的保活定時器可以提供這種能力。保活並不是TCP規範中的一部分。

保活就是:防止兩端的TCP在連接期間長時間處於空暇狀態。一般是server設置的計時器,超時通常設置爲2h,當server超過了2h還沒有收到客戶的任何信息,server就向客戶發送過一個探測報文段,若連續發送了10個探測報文段(每個75s一個)還沒有響應,就覺得客戶出了故障,直接終止這個連接。

  • 保活定時器工作原理:

如果一個 給定的連接在2小時內沒有任何動作,那麼服務器就向客戶發送一個探查報文段。客戶主機必須處於以下4個狀態之一:
(1)客戶主機依然正常運行,並從服務器可達。客戶的TCP響應正常,而服務器也知道對方的正常工作的,服務器在2小時內將保活定時器復位。
(2)客戶主機已經崩潰,並且關閉或者正在重新啓動。在任何一種情況下,客戶的TCP都沒有響應,服務器將不能收到對探查的響應,並在75秒後超時,總共發送10個探查,每個間隔75秒。如果服務器沒有收到一個響應,它就認爲客戶主機已經關閉並終止連接。
(3)客戶主機崩潰並已經重新啓動。這是服務器將收到一個對其保活探查的響應,但這個響應是一個RST復位,使得服務器終止這個連接。
(4)客戶主機正常運行,但是從服務器不可達。這與狀態2相同,因爲TCP不能夠區分狀態4與2之間的區別,它所能發現的就是沒有收到探查的響應。

服務器不用關注客戶主機被關閉和重新啓動的情況,當系統被操作員關閉時,所有的應用進程也被終止,這會使客戶的TCP在連接上發出一個FIN。接收到FIN將使服務器的TCP向服務器進程報告文件結束,使服務器可以檢測到這個情況。

6.FIN_WAIT_2定時器(FIN_WAIT_2 timer)

在主動關閉的一端調用完close以後(發FIN包給對端, 並且收到對端對FIN的ACK)則進入到FIN_WAIT_2狀態,那麼這個時候如果和對端之間的網絡壞了或者對端程序有問題了一直不close,或者對端機器直接斷電了,本端不能一直傻等吧,所以就需要這個定時器,如果在這個定時器超時的時候,還是沒收到對端的FIN包,那麼不好意思不等了,直接釋放這個鏈接。

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

在連接終止期使用,當TCP關閉連接時,並不認爲這個連接就真正關閉了,在時間等待期間,連接還處於一種中間過度狀態。這樣就可以使重複的FIN報文段在到達終點後被丟棄,這個計時器的值通常設置爲一格報文段壽命期望值的兩倍。

·TIME_WAIT是主動關閉連接的一端最後進入的狀態,而不是直接變成CLOSED的狀態,爲什麼呢?

  • 第一個原因是萬一最後一個ACK丟失了,對端會重傳的,這個在超時之前的重新收到對端的FIN也可以回ACK,而不是RST。
  • 另外一個原因是防止老連接的包在新連接裏面出現,影響了新連接。有這個2MSL的時間,可以在2個MSL時間之內不會建立同樣四元組(源IP, 源端口,目的IP,目的端口)的連接,也就不會出現老的包影響新連接的事情。

·爲什麼TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSE狀態?

MSL(Maximum Segment Lifetime)表示報文段最大生存時間,它表示任何報文段被丟棄前在網絡內的最長時間,實際上這個時間和 TTL 有關(TTL 是 IP 協議中的一個概念,表示能夠經歷的路由器的跳數,這個跳數是有限制的,最大值爲 255)。但是MSL並不用跳數,而是用時間來計算。不同系統中,MSL 定義的大小不一樣RFC 規定,MSL = 2 分鐘,而實際實現中,通常是 30 秒、1 分鐘。也就是說報文在網絡中存在的時間不能超過MSL規定的時間,同時也間接的說明了tcp連接在TIME_WAIT狀態必須存在2MSL才能進入CLOSE狀態。

參考鏈接:TIME_WAIT詳解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章