眾所周知,TCP協(xié)議是一個可靠的的協(xié)議。TCP的可靠性依賴于大量的 Timer 和 Retransmission ∑恚現(xiàn)在咱們就來細(xì)說一下TCP協(xié)議的那些Timer
Connection-Establishment Timer
在TCP三次握手創(chuàng)建一個連接時,以下兩種情況會發(fā)生超時:
1.client發(fā)送SYN后幻枉,進入SYN_SENT狀態(tài)剑梳,等待server的SYN+ACK苗傅。
2.server收到連接創(chuàng)建的SYN,回應(yīng)SYN+ACK后缸浦,進入SYN_RECD狀態(tài)夕冲,等待client的ACK。
當(dāng)超時發(fā)生時裂逐,就會重傳歹鱼,一直到75s還沒有收到任何回應(yīng),便會放棄卜高,終止連接的創(chuàng)建弥姻。但是在Linux實現(xiàn)中南片,并不是依靠超時總時間來判斷是否終止連接。而是依賴重傳次數(shù):
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.
Retransmission Timer
當(dāng)三次握手成功庭敦,連接建立疼进,發(fā)送TCP segment,等待ACK確認(rèn)秧廉。如果在指定時間內(nèi)伞广,沒有得到ACK,就會重傳疼电,一直重傳到放棄為止赔癌。Linux中也有相關(guān)變量來設(shè)置這里的重傳次數(shù)的:
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.
Delayed ACK Timer
當(dāng)一方接受到TCP segment,需要回應(yīng)ACK澜沟。但是不需要 立即 發(fā)送灾票,而是等上一段時間,看看是否有其他數(shù)據(jù)可以 捎帶 一起發(fā)送茫虽。這段時間便是 Delayed ACK Timer 刊苍,一般為200ms。
Persist Timer
如果某一時刻濒析,一方發(fā)現(xiàn)自己的 socket read buffer 滿了正什,無法接受更多的TCP data,此時就是在接下來的發(fā)送包中指定通告窗口的大小為0号杏,這樣對方就不能接著發(fā)送TCP data了婴氮。如果socket read buffer有了空間,可以重設(shè)通告窗口的大小在接下來的 TCP segment 中告知對方盾致≈骶可是萬一這個 TCP segment 不附帶任何data,所以即使這個segment丟失也不會知曉(ACKs are not acknowledged, only data is acknowledged)庭惜。對方?jīng)]有接受到罩驻,便不知通告窗口的大小發(fā)生了變化,也不會發(fā)送TCP data护赊。這樣雙方便會一直僵持下去惠遏。
TCP協(xié)議采用這個機制避免這種問題:對方即使知道當(dāng)前不能發(fā)送TCP data,當(dāng)有data發(fā)送時骏啰,過一段時間后节吮,也應(yīng)該嘗試發(fā)送一個字節(jié)。這段時間便是 Persist Timer 判耕。
Keepalive Timer
TCP socket 的 SO_KEEPALIVE option透绩,主要適用于這種場景:連接的雙方一般情況下沒有數(shù)據(jù)要發(fā)送,僅僅就想嘗試確認(rèn)對方是否依然在線。目前vipbar網(wǎng)吧渺贤,判斷當(dāng)前客戶端是否依然在線雏胃,就用的是這個option请毛。
具體實現(xiàn)方法:TCP每隔一段時間(tcp_keepalive_intvl)會發(fā)送一個特殊的 Probe Segment志鞍,強制對方回應(yīng),如果沒有在指定的時間內(nèi)回應(yīng)方仿,便會重傳固棚,一直到重傳次數(shù)達到 tcp_keepalive_probes 便認(rèn)為對方已經(jīng)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.
FIN_WAIT_2 Timer
當(dāng)主動關(guān)閉方想關(guān)閉TCP connection仙蚜,發(fā)送FIN并且得到相應(yīng)ACK此洲,從FIN_WAIT_1狀態(tài)進入FIN_WAIT_2狀態(tài),此時不能發(fā)送任何data了委粉,只等待對方發(fā)送FIN呜师。可以萬一對方一直不發(fā)送FIN呢贾节?這樣連接就一直處于FIN_WAIT_2狀態(tài)汁汗,也是很經(jīng)典的一個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.
TIME_WAIT Timer
TIME_WAIT Timer存在的原因和必要性斤程,主要是兩個方面:
主動關(guān)閉方發(fā)送了一個ACK給對方角寸,假如這個ACK發(fā)送失敗,并導(dǎo)致對方重發(fā)FIN信息忿墅,那么這時候就需要TIME_WAIT狀態(tài)來維護這次連接扁藕,因為假如沒有TIME_WAIT,當(dāng)重傳的FIN到達時疚脐,TCP連接的信息已經(jīng)不存在纹磺,所以就會重新啟動消息應(yīng)答,會導(dǎo)致對方進入錯誤的狀態(tài)而不是正常的終止?fàn)顟B(tài)亮曹。假如主動關(guān)閉方這時候處于TIME_WAIT橄杨,那么仍有記錄這次連接的信息,就可以正確響應(yīng)對方重發(fā)的FIN了照卦。
一個數(shù)據(jù)報在發(fā)送途中或者響應(yīng)過程中有可能成為殘余的數(shù)據(jù)報式矫,因此必須等待足夠長的時間避免新的連接會收到先前連接的殘余數(shù)據(jù)報,而造成狀態(tài)錯誤役耕。
但是我至今疑惑的是:為什么這個超時時間的值為2MSL采转?如果為了保證雙方向的TCP包要么全部響應(yīng)完畢,要么全部丟棄不對新連接造成干擾,這個時間應(yīng)該是:
被動關(guān)閉方LAST_ACK的超時時間 + 1MSL
因為被動關(guān)閉方進入LAST_ACK狀態(tài)后故慈,假設(shè)一直沒有收到最后一個ACK板熊,會一直重傳FIN,一直重傳次數(shù)到達TCP_RETRIES放棄察绷,將這個時間定義為「被動關(guān)閉方LAST_ACK的超時時間」干签,接著必須等待最后一個重傳的FIN失效,需要一個MSL的時間拆撼。這樣才能保證所有重傳的FIN包失效容劳,不干擾新連接吧。