网络:TCP维护安全可靠机制提供的定时器
一、TCP為維護(hù)安全可靠機(jī)制提供了七大定時(shí)器
?
1、連接建立(connectionestablishment)”定時(shí)器:
?????? 在發(fā)送SYN報(bào)文段建立一條新連接時(shí)啟動(dòng)。如果在75秒內(nèi)沒有收到響應(yīng),連接建立將中止。
?
2、重傳(retransmission)定時(shí)器:
?????? 在TCP發(fā)送某個(gè)數(shù)據(jù)段時(shí)設(shè)定。如果該定時(shí)器超時(shí)而對(duì)端的確認(rèn)還未到達(dá),TCP將重傳該數(shù)據(jù)段。重傳定時(shí)器的值 (即TCP等待對(duì)端確認(rèn)的時(shí)間)是動(dòng)態(tài)計(jì)算的,與RTT的估計(jì)值密切相關(guān),且還取決于該報(bào)文段已被重傳的次數(shù)。
?
3、延遲ACK(delayedACK)定時(shí)器:
?????? 在TCP收到必須被確認(rèn)但無(wú)需馬上發(fā)出確認(rèn)的數(shù)據(jù)時(shí)設(shè)定。如果在200ms內(nèi),有數(shù)據(jù)要在該連接上發(fā)送,延遲的ACK響應(yīng)就可隨著數(shù)據(jù)一起發(fā)送回對(duì)端,稱為捎帶確認(rèn)。如果200ms后,該確認(rèn)未能被捎帶出去,則定時(shí)器超時(shí),此時(shí)需要發(fā)送一個(gè)立即確認(rèn)。
?
4、持續(xù)(persist)定時(shí)器(零窗口探測(cè)定時(shí)器(PT0)):
?????? 在連接對(duì)端通告接收窗口為0,阻止TCP繼續(xù)發(fā)送數(shù)據(jù)時(shí)設(shè)定。由于連接對(duì)端發(fā)送的窗口通告不可靠(只有數(shù)據(jù)才會(huì)被確認(rèn),ACK不會(huì)被確認(rèn)),允許TCP繼續(xù)發(fā)送數(shù)據(jù)的后續(xù)窗口更新有可能丟失。因此,如果TCP有數(shù)據(jù)要發(fā)送,但對(duì)端通告接收窗口為0,則持續(xù)定時(shí)器啟動(dòng),超時(shí)后向?qū)Χ税l(fā)送 1字節(jié)的數(shù)據(jù),判定對(duì)端接收窗口是否已打開。
?
5、?;?keepalive)定時(shí)器:
?????? 在TCP控制塊的so_options 字段設(shè)置了SOF_KEEPALIVE選項(xiàng)時(shí)生效。如果連接的連續(xù)空閑時(shí)間超過2小時(shí),則?;疃〞r(shí)器超時(shí),此時(shí)應(yīng)向?qū)Χ税l(fā)送連接探測(cè)報(bào)文段,強(qiáng)迫對(duì)端響應(yīng)。如果收到了期待的響應(yīng), TCP可確定對(duì)端主機(jī)工作正常,在該連接再次空閑超過 2小時(shí)之前,TCP不會(huì)再進(jìn)行保活測(cè)試。如果收到的是RST復(fù)位響應(yīng), TCP可確定對(duì)端主機(jī)已重啟。如果連續(xù)若干次?;顪y(cè)試都未收到響應(yīng), TCP就假定對(duì)端主機(jī)已崩潰,但它無(wú)法區(qū)分是主機(jī)故障還是連接故障。
?
6、FIN_WAIT_2定時(shí)器:
?????? 當(dāng)某個(gè)連接從FIN_WAIT_1狀態(tài)變遷到FIN_WAIT_2狀態(tài)并且不能再接收任何新數(shù)據(jù)時(shí),FIN_WAIT_2定時(shí)器啟動(dòng),設(shè)為10分鐘。定時(shí)器超時(shí)后,重新設(shè)為75秒,第二次超時(shí)后連接被關(guān)閉。加入這個(gè)定時(shí)器的目的是為了避免如果對(duì)端一直不發(fā)送 FIN,某個(gè)連接會(huì)永遠(yuǎn)滯留在FIN _ WAIT_ 2狀態(tài)(假設(shè)TCP不選用半打開功能)。
?
7、TIME_WAIT定時(shí)器(2MSL定時(shí)器):
?????? 2MSL指兩倍的MSL,即最大報(bào)文段生存時(shí)間。當(dāng)連接轉(zhuǎn)移到TIME_WAIT狀態(tài),即連接主動(dòng)關(guān)閉時(shí),定時(shí)器啟動(dòng)。狀態(tài)轉(zhuǎn)換圖那一節(jié)中已經(jīng)詳細(xì)說明了需要2MSL等待狀態(tài)的原因。連接進(jìn)入TIME_WAIT狀態(tài)時(shí),定時(shí)器設(shè)定為1分鐘,超時(shí)后,TCP控制塊被刪除,端口號(hào)可重新使用。
?
8、SYN|ACK定時(shí)器:
?????? TCP服務(wù)器在收到SYN請(qǐng)求后發(fā)送SYN|ACK響應(yīng),TCP在發(fā)送SYN|ACK響應(yīng)后設(shè)置SYN-ACK定時(shí)器,然后等待對(duì)端的ACK到來(lái)以完成三次握手。如果沒有收到ACK,TCP應(yīng)該重傳SYN|ACK,這個(gè)功能由SYN-ACK定時(shí)器完成。由于SYN|ACK發(fā)送后并沒有放入發(fā)送隊(duì)列中,故重傳時(shí)必須重新構(gòu)建SYN|ACK報(bào)文。?
?
9、ER延時(shí)定時(shí)器:
?????? TCP發(fā)送的數(shù)據(jù)如果丟失則快速重傳算法會(huì)立即重傳數(shù)據(jù)而不用等到重傳定時(shí)器超時(shí),從而快速地恢復(fù)數(shù)據(jù)。如果發(fā)送端接收不到足夠數(shù)量(一般來(lái)說是3個(gè))的ACK,則快重傳算法無(wú)法起作用,這個(gè)時(shí)候就只能等待RTO超時(shí)。ER算法主要是為了解決這個(gè)問題。
?????? 在下面的條件下,就會(huì)導(dǎo)致收不到足夠的ACK:
?????? (1)擁塞窗口比較小
?????? (2)窗口中一個(gè)很大數(shù)量的段丟失或者在傳輸?shù)慕Y(jié)尾處發(fā)生了丟包
???????? 如果滿足了上面的兩個(gè)條件,那么就會(huì)發(fā)生發(fā)送端由于接收不到足夠數(shù)量的ACK導(dǎo)致ER可以基于兩種模式,一種是基于字節(jié)的,一種是基于段(segment-based)的,Linux中的ER是基于段的。ER算法會(huì)在小窗口下(flight count 小于4)減小觸發(fā)快重傳的重復(fù)ACK的閾值,比如減小到1或者2。而在Linux的實(shí)現(xiàn)中為了防止假超時(shí)會(huì)加上一個(gè)延遲再重傳數(shù)據(jù),這個(gè)功能就靠ER定時(shí)器實(shí)現(xiàn)??熘貍魉惴o(wú)法生效.
?
?????? 在這些條件滿足后,ER定時(shí)器會(huì)被設(shè)置,其超時(shí)時(shí)間是一個(gè)比重傳定時(shí)器更小的值。
??????? 安裝丟失探測(cè)定時(shí)器、重傳定時(shí)器、堅(jiān)持定時(shí)器時(shí)ER定時(shí)器就會(huì)被清除。
??????
?????? (1)有丟包事件發(fā)生
?????? (2)重復(fù)的ACK小于等于亂序的閾值
?????? (3)未開啟FACK,或沒有未收到確認(rèn)的包,或隊(duì)列首包已發(fā)送但未超時(shí)
?????? (4)已發(fā)送的數(shù)據(jù) > 亂序的閾值,或被SACK段的數(shù)量小于閾值,或允許發(fā)送skb
(5)thin_dupack功能未開啟,或當(dāng)前鏈接并不是"thin"的,或重復(fù)ACK的數(shù)量大于1,或SACK未開啟,或有要發(fā)送的數(shù)據(jù)
?????? (6)do_early_retrans開啟
?????? (7)沒有重傳完畢但沒有確認(rèn)的報(bào)文
?????? (8)有被SACK的報(bào)文
?????? (9)在網(wǎng)絡(luò)中的報(bào)文數(shù)量比被SACK的報(bào)文數(shù)量多至少1個(gè)
?????? (10)在網(wǎng)絡(luò)中的報(bào)文數(shù)量少于4
?????? (11)現(xiàn)在不允許發(fā)送數(shù)據(jù)
?????? (12)sysctl_tcp_early_retrans的值是2或3
?????? (13)ACK中沒有ECE標(biāo)記
?????? (14)tp->srtt(smoothed round trip time)的值大于0
?????? (15)icsk->icsk_retransmit_timer超時(shí)時(shí)間在延遲時(shí)間之后
??????????? 值得注意的是在快速重傳時(shí)不會(huì)重傳已經(jīng)被SACK過或被重傳過的skb,這些skb也許能夠順利收到,在這里不重傳會(huì)減小網(wǎng)絡(luò)擁塞。
?
?
雖然定義了9個(gè)定時(shí)器,但是內(nèi)核中只用了4個(gè)實(shí)例(timer_list),所以有些定時(shí)器是共用一個(gè)實(shí)例的。
這4個(gè)實(shí)例分別是:
icsk->icsk_retransmit_timer:超時(shí)重傳定時(shí)器、持續(xù)定時(shí)器、ER延遲定時(shí)器、PTO定時(shí)器。
icsk->icsk_delack_timer:ACK延遲定時(shí)器。
sk->sk_timer:?;疃〞r(shí)器,SYNACK定時(shí)器,FIN_WAIT2定時(shí)器。
death_row->tw_timer:TIME_WAIT定時(shí)器
?
?
二、TCP要保證正常工作,至少應(yīng)該有四種計(jì)時(shí)器:重傳計(jì)時(shí)器、持久計(jì)時(shí)器、?;钣?jì)時(shí)器和時(shí)間等待計(jì)時(shí)器。
?
1、??? 重傳計(jì)時(shí)器:
?
超時(shí)重傳是TCP協(xié)議保證數(shù)據(jù)可靠性的另一個(gè)重要機(jī)制,其原理是在發(fā)送某一個(gè)數(shù)據(jù)以后就開啟一個(gè)計(jì)時(shí)器,在一定時(shí)間內(nèi)如果沒有得到發(fā)送的數(shù)據(jù)報(bào)的ACK報(bào)文,那么就重新發(fā)送數(shù)據(jù),直到發(fā)送成功為止。當(dāng)TCP發(fā)送報(bào)文段時(shí),就創(chuàng)建該特定報(bào)文段的重傳計(jì)時(shí)器。
可能發(fā)生兩種情況:
?1) 若在計(jì)時(shí)器截止時(shí)間到之前收到了對(duì)此特定報(bào)文段的確認(rèn),則撤銷此計(jì)時(shí)器。
?2)收到了對(duì)此特定報(bào)文段的確認(rèn)之前計(jì)時(shí)器截止期到,則重傳此報(bào)文段,并將計(jì)時(shí)器復(fù)位。
?
1.重傳超時(shí)時(shí)間:
?
???重傳機(jī)制協(xié)議效率的一個(gè)關(guān)鍵參數(shù)是重傳超時(shí)時(shí)間(RTO,Retransmission TimeOut)。RTO的值被設(shè)置過大過小都會(huì)對(duì)協(xié)議造成不利影響。如果RTO設(shè)置過大將會(huì)使發(fā)送端經(jīng)過較長(zhǎng)時(shí)間的等待才能發(fā)現(xiàn)報(bào)文段丟失,降低了連接數(shù)據(jù)傳輸?shù)耐掏铝?#xff1b;另一方面,若RTO過小,發(fā)送端盡管可以很快地檢測(cè)出報(bào)文段的丟失,但也可能將一些延遲大的報(bào)文段誤認(rèn)為是丟失,造成不必要的重傳,浪費(fèi)了網(wǎng)絡(luò)資源。
如果底層網(wǎng)絡(luò)的傳輸特性是可預(yù)知的,那么重傳機(jī)制的設(shè)計(jì)相對(duì)簡(jiǎn)單得多,可根據(jù)底層網(wǎng)絡(luò)的傳輸時(shí)延的特性選擇一個(gè)合適的RTO,使協(xié)議的性能得到優(yōu)化。但是TCP的底層網(wǎng)絡(luò)環(huán)境是一個(gè)完全異構(gòu)的互聯(lián)結(jié)構(gòu)。在實(shí)現(xiàn)端到端的通信時(shí),不同端點(diǎn)之間傳輸通路的性能可能存在著巨大的差異,而且同一個(gè)TCP連接在不同的時(shí)間段上,也會(huì)由于不同的網(wǎng)絡(luò)狀態(tài)具有不同的傳輸時(shí)延。
因次,TCP協(xié)議必須適應(yīng)兩個(gè)方面的時(shí)延差異:一個(gè)是達(dá)到不同目的端的時(shí)延的差異,另一個(gè)是統(tǒng)一連接上的傳輸時(shí)延隨業(yè)務(wù)量負(fù)載的變化而出現(xiàn)的差異。為了處理這種底層網(wǎng)絡(luò)傳輸特性的差異性和變化性,TCP的重傳機(jī)制相對(duì)于其他協(xié)議顯然也將更為復(fù)雜,其復(fù)雜性主要表現(xiàn)在對(duì)超時(shí)時(shí)間間隔的處理上。為此,TCP協(xié)議使用自適應(yīng)算法(AdaptiveRetransmissionAlgorithm)以適應(yīng)互聯(lián)網(wǎng)分組傳輸時(shí)延的變化。這種算法的基本要點(diǎn)是TCP監(jiān)視每個(gè)連接的性能(即傳輸時(shí)延),由此每一個(gè)TCP連接推算出合適的RTO值,當(dāng)連接時(shí)延性能變化時(shí),TCP也能夠相應(yīng)地自動(dòng)修改RTO的設(shè)定,以適應(yīng)這種網(wǎng)絡(luò)的變化。
??
2.連接往返時(shí)間:
?
??個(gè)連接而言,若能夠了解端點(diǎn)間的傳輸往返時(shí)間(RTT,Round Trip Time),則可根據(jù)RTT來(lái)設(shè)置一合適的RTO。顯然,在任何時(shí)刻連接的RTT都是隨機(jī)的,無(wú)法事先預(yù)知。TCP通過測(cè)量來(lái)獲得連接當(dāng)前RTT的一個(gè)估計(jì)值,并以該RTT估計(jì)值為基準(zhǔn)來(lái)設(shè)置當(dāng)前的RTO。自適應(yīng)重傳算法的關(guān)鍵就在于對(duì)當(dāng)前RTT的準(zhǔn)確估計(jì),以便適時(shí)調(diào)整RTO。
為了搜集足夠的數(shù)據(jù)來(lái)精確地估算當(dāng)前的RTT,TCP對(duì)每個(gè)報(bào)文都記錄下發(fā)送出的時(shí)間和收到的確認(rèn)時(shí)間。每一個(gè)(發(fā)送時(shí)間,確認(rèn)時(shí)間)對(duì)就可以計(jì)算出一個(gè)RTT測(cè)量值的樣本(Sample RTT)。TCP為每一個(gè)活動(dòng)的連接都維護(hù)一個(gè)當(dāng)前的RTT估計(jì)值。該值是對(duì)已經(jīng)過去的一個(gè)時(shí)間段內(nèi)該連接的RTT了兩只的加權(quán)平均,并作為TCP對(duì)連接當(dāng)前實(shí)際的RTT值的一種估計(jì)。RTT估計(jì)值將在發(fā)送報(bào)文段時(shí)被用于確定報(bào)文段的RTO。為了保證它能夠比較準(zhǔn)確地反應(yīng)當(dāng)前的網(wǎng)絡(luò)狀態(tài),每當(dāng)TCP通過測(cè)量獲得了個(gè)新的RTT樣本時(shí),都將對(duì)RTT的估計(jì)值進(jìn)行更新。不同的更新算法或參數(shù)可能獲得不同的特性。[1]
最早的TCP曾經(jīng)用了一個(gè)非常簡(jiǎn)單的公式來(lái)估計(jì)當(dāng)前網(wǎng)絡(luò)的狀況,如下
R<-aR+(1-a)MRTP=Rb其中a是一個(gè)經(jīng)驗(yàn)系數(shù)為0.1,b通常為2。注意,這是經(jīng)驗(yàn),沒有推導(dǎo)過程,這個(gè)數(shù)值是可以被修改的。這個(gè)公式是說用舊的RTT(R)和新的RTT (M)綜合到一起來(lái)考慮新的RTT(R)的大小。但又可以看到,這種估計(jì)在網(wǎng)絡(luò)變化很大的情況下完全不能做出“靈敏的反應(yīng)”,于是就有下面的修正公式:
Err=M-AA<-A+gErrD<-D+h(|Err|-D)RTO=A+4D,這個(gè)遞推公式甚至把方差這種統(tǒng)計(jì)概念也使用了進(jìn)來(lái),使得偏差更加的小。而且,必須要指出的是,這兩組公式更新,都是在 數(shù)據(jù)成功傳輸?shù)那闆r下才進(jìn)行,在發(fā)生數(shù)據(jù)重新傳輸?shù)那闆r下,并不使用上面的公式進(jìn)行網(wǎng)絡(luò)估計(jì),理由很簡(jiǎn)單,因?yàn)槌绦蛞呀?jīng)不在正常狀態(tài)下了,估計(jì)出來(lái)的數(shù)據(jù)也是沒有意義的。
如果在一個(gè)報(bào)文段中的數(shù)據(jù)被一次性地成功傳輸和確認(rèn),那么發(fā)送端可以準(zhǔn)確得到該報(bào)文段傳輸?shù)腞TT樣本。但若出現(xiàn)了重傳,情況就會(huì)變得很復(fù)雜。例如,一個(gè)報(bào)文段發(fā)送后出現(xiàn)超時(shí),TCP將在另一個(gè)報(bào)文段中重傳。由于這兩個(gè)報(bào)文段包含了同樣的數(shù)據(jù),發(fā)送方接收到確認(rèn)信息時(shí)將無(wú)法分辨出確認(rèn)信息到底是針對(duì)哪個(gè)報(bào)文段的,因?yàn)檫@兩個(gè)報(bào)文段產(chǎn)生的確認(rèn)信息可能是完全相同的,確認(rèn)信息既可能是針對(duì)原始報(bào)文段的(這種情況可能是由于原報(bào)文段或確認(rèn)在傳輸中被延遲造成的),也可能是對(duì)重傳報(bào)文段的確認(rèn)。這種現(xiàn)象稱為確認(rèn)二義性(Acknowledgement Ambiguiity)。確認(rèn)的二義性將導(dǎo)致TCP無(wú)法準(zhǔn)確地估算RTT。
為了避免確認(rèn)二義性帶來(lái)的問題,TCP采用了Karn算法來(lái)維護(hù)RTT的估計(jì)值。Karn算法規(guī)定,TCP只能利用沒有確認(rèn)二義性(既無(wú)重發(fā)、一次發(fā)送成功并得到確認(rèn)的報(bào)文段)的RTT樣本來(lái)對(duì)RTT的估計(jì)值進(jìn)行調(diào)整。
?
?
?
2、??? 堅(jiān)持計(jì)時(shí)器
?
??? 過讓接收方指明希望從發(fā)送方接收的數(shù)據(jù)字節(jié)數(shù)(即窗口大小)來(lái)進(jìn)行流量控制。如果窗口大小為 0,這將有效地阻止發(fā)送方傳送數(shù)據(jù),直到窗口變?yōu)榉?為止。TCP不對(duì)ACK報(bào)文段進(jìn)行確認(rèn), TCP只確認(rèn)那些包含有數(shù)據(jù)的ACK報(bào)文段。如果一個(gè)確認(rèn)丟失了,則雙方就有可能因?yàn)榈却龑?duì)方而使連接終止:接收方等待接收數(shù)據(jù)(因?yàn)樗呀?jīng)向發(fā)送方通告了一個(gè)非 0的窗口),而發(fā)送方在等待允許它繼續(xù)發(fā)送數(shù)據(jù)的窗口更新。為防止這種死鎖情況的發(fā)生,發(fā)送方使用一個(gè)堅(jiān)持定時(shí)器 (persist timer)來(lái)周期性地向接收方查詢,以便發(fā)現(xiàn)窗口是否已增大。這些從發(fā)送方發(fā)出的報(bào)文段稱為窗口探查 (window? probe)。這個(gè)報(bào)文段只有一個(gè)字節(jié)的數(shù)據(jù)。它有一個(gè)序號(hào),但它的序號(hào)永遠(yuǎn)不需要確認(rèn);甚至在計(jì)算對(duì)其他部分的數(shù)據(jù)的確認(rèn)時(shí)該序號(hào)也被忽略。探測(cè)報(bào)文段提醒接收TCP:確認(rèn)已丟失,必須重傳。
堅(jiān)持計(jì)時(shí)器的值設(shè)置為重傳時(shí)間的數(shù)值。但是,若沒有收到從接收端來(lái)的響應(yīng),則需發(fā)送另一個(gè)探測(cè)報(bào)文段,并將堅(jiān)持計(jì)時(shí)器的值加倍和復(fù)位。發(fā)送端繼續(xù)發(fā)送探測(cè)報(bào)文段,將堅(jiān)持計(jì)時(shí)器設(shè)定的值加倍和復(fù)位,直到這個(gè)值增大到門限值(通常是60秒)為止。在這以后,發(fā)送端每隔60秒就發(fā)送一個(gè)探測(cè)報(bào)文段,直到窗口重新打開。
?
3、??? ?;钣?jì)時(shí)器
?
??????? ?;钣?jì)時(shí)器使用在某些實(shí)現(xiàn)中,用來(lái)防止在兩個(gè)TCP之間的連接出現(xiàn)長(zhǎng)時(shí)期的空閑。假定客戶打開了到服務(wù)器的連接,傳送了一些數(shù)據(jù),然后就保持靜默了。也許這個(gè)客戶出故障了。在這種情況下,這個(gè)連接將永遠(yuǎn)地處理打開狀態(tài)。
要解決這種問題,在大多數(shù)的實(shí)現(xiàn)中都是使服務(wù)器設(shè)置保活計(jì)時(shí)器。每當(dāng)服務(wù)器收到客戶的信息,就將計(jì)時(shí)器復(fù)位。超時(shí)通常設(shè)置為2小時(shí)。若服務(wù)器過了2小時(shí)還沒有收到客戶的信息,它就發(fā)送探測(cè)報(bào)文段。若發(fā)送了10個(gè)探測(cè)報(bào)文段(每一個(gè)相隔75秒)還沒有響應(yīng),就假定客戶出了故障,因而就終止該連接。
這種連接的斷開當(dāng)然不會(huì)使用四次握手,而是直接硬性地中斷和客戶端的TCP連接。
??? 如果一個(gè)給定的連接在兩個(gè)小時(shí)之內(nèi)沒有任何動(dòng)作,則服務(wù)器就向客戶發(fā)送一個(gè)探查報(bào)文段??蛻魴C(jī)處于以下4種狀態(tài)之一時(shí),發(fā)送探查報(bào)文。
1、客戶主機(jī)依然正常運(yùn)行,并從服務(wù)器可達(dá)??蛻魴C(jī)的TCP響應(yīng)正常,而服務(wù)器也知道對(duì)方正常工作的。服務(wù)器在兩小時(shí)以后將保活定時(shí)器復(fù)位,如果在兩個(gè)小時(shí)定時(shí)器到時(shí)間之前有應(yīng)用程序的通信量通過此連接,則定時(shí)器在交換數(shù)據(jù)后的未來(lái)2小時(shí)復(fù)位。
?
2、客戶機(jī)已經(jīng)崩潰,并且關(guān)閉或正在重新啟動(dòng),在任何一種情況下,客戶的TCP都沒有響應(yīng),服務(wù)器將不能夠收到對(duì)探查的響應(yīng),并在75秒后超時(shí),服務(wù)器總共發(fā)送10個(gè)這樣的探查,每個(gè)間隔75秒,如果服務(wù)器沒有收到一個(gè)響應(yīng),它就認(rèn)為客戶主機(jī)已經(jīng)關(guān)閉并終止連接。
socket函數(shù)會(huì)返回-1,errno設(shè)置為ETIMEDOUT,表示連接超時(shí)。
?
3、客戶主機(jī)崩潰并已經(jīng)重新啟動(dòng),這時(shí)服務(wù)器將收到一個(gè)對(duì)其保活探查的響應(yīng),但是這個(gè)響應(yīng)是一個(gè)復(fù)位,使得服務(wù)器終止這個(gè)連接??蛻舳说腡CP發(fā)送RST,服務(wù)器端收到后關(guān)閉此連接。
socket函數(shù)會(huì)返回-1,errno設(shè)置為ECONNRESET,表示連接被對(duì)端復(fù)位了
?
4、客戶機(jī)正常運(yùn)行,但是從服務(wù)器不可達(dá),這與狀態(tài)2相同,因?yàn)門CP不能夠區(qū)分狀態(tài)4與狀態(tài)2之間的區(qū)別,它所能發(fā)現(xiàn)的就是沒有收到探查的響應(yīng)。
服務(wù)器不用關(guān)注客戶主機(jī)被關(guān)閉和重新啟動(dòng)的情況,當(dāng)系統(tǒng)被操作員半閉時(shí),所的應(yīng)用進(jìn)程也被終止,這會(huì)使客戶的TCP在連接上發(fā)了一個(gè)FIN,接收到FIN將使服務(wù)器的TCP響服務(wù)器進(jìn)程報(bào)告文件結(jié)束,使服務(wù)器可以檢測(cè)到這個(gè)情況。雙方的反應(yīng)和第二種是一樣的,因?yàn)榉?wù)器不能區(qū)分對(duì)端異常與中間鏈路異常。
socket函數(shù)會(huì)返回-1,errno設(shè)置為EHOSTUNREACH,表示對(duì)端不可達(dá)
?
內(nèi)核默認(rèn)并不使用TCPKeepalive功能,除非用戶設(shè)置了SO_KEEPALIVE選項(xiàng)。
有兩種方式可以自行調(diào)整保活定時(shí)器的參數(shù):一種是修改TCP參數(shù),一種是使用TCP層選項(xiàng)。
?
(1) TCP參數(shù)
tcp_keepalive_time
最后一次數(shù)據(jù)交換到TCP發(fā)送第一個(gè)保活探測(cè)報(bào)文的時(shí)間,即允許連接空閑的時(shí)間,默認(rèn)為7200s。
tcp_keepalive_intvl
?;钐綔y(cè)報(bào)文的重傳時(shí)間,默認(rèn)為75s。
tcp_keepalive_probes
?;钐綔y(cè)報(bào)文的發(fā)送次數(shù),默認(rèn)為9次。
?一次完整的保活探測(cè)需要花費(fèi)時(shí)間tcp_keepalive_time + tcp_keepalive_intvl*tcp_keepalive_probes,默認(rèn)值為7875s。
如果覺得兩個(gè)多小時(shí)太長(zhǎng)了,可以自行調(diào)整上述參數(shù)。
?
(2) TCP層選項(xiàng)
TCP_KEEPIDLE:含義同tcp_keepalive_time。
TCP_KEEPINTVL:含義同tcp_keepalive_intvl。
TCP_KEEPCNT:含義同tcp_keepalive_probes。
??? TCP參數(shù)是面向本機(jī)的所有TCP連接,一旦調(diào)整了,對(duì)所有的連接都有效。
而TCP層選項(xiàng)是面向一條連接的,一旦調(diào)整了,只對(duì)本條連接有效。
?激活
?在連接建立后,可以通過設(shè)置SO_KEEPALIVE選項(xiàng),來(lái)激活保活定時(shí)器。
int keepalive = 1;
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,&keepalive,sizeof(keepalive));
可以使用TCP層選項(xiàng)來(lái)動(dòng)態(tài)調(diào)整?;疃〞r(shí)器的參數(shù)。
int keepidle = 600;
int keepintvl = 10;
int keepcnt = 6;
setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &keepidle,sizeof(keepidle));
setsockopt(fd, SOL_TCP, TCP_KEEPINTVL,&keepintvl,sizeof(keepintvl));
setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &keepcnt,sizeof(keepcnt));
?
LinuxSO_KEEPALIVE屬性,心跳包
對(duì)于面向連接的TCP socket,在實(shí)際應(yīng)用中通常都要檢測(cè)對(duì)端是否處于連接中,連接端口分兩種情況:
1、連接正常關(guān)閉,調(diào)用close() shutdown()連接優(yōu)雅關(guān)閉,send與recv立馬返回錯(cuò)誤,select返回SOCK_ERR;
2、連接的對(duì)端異常關(guān)閉,比如網(wǎng)絡(luò)斷掉,突然斷電.
對(duì)于第二種情況,判斷連接是否斷開的方法有一下幾種:
1、自己編寫心跳包程序,簡(jiǎn)單的說就是自己的程序加入一條線程,定時(shí)向?qū)Χ税l(fā)送數(shù)據(jù)包,查看是否有ACK,根據(jù)ACK的返回情況來(lái)管理連接。此方法比較通用,一般使用業(yè)務(wù)層心跳處理,靈活可控,但改變了現(xiàn)有的協(xié)議;
2、使用TCP的keepalive機(jī)制,UNIX網(wǎng)絡(luò)編程不推薦使用SO_KEEPALIVE來(lái)做心跳檢測(cè)。
keepalive原理:TCP內(nèi)嵌有心跳包,以服務(wù)端為例,當(dāng)server檢測(cè)到超過一定時(shí)間(/proc/sys/net/ipv4/tcp_keepalive_time7200 即2小時(shí))沒有數(shù)據(jù)傳輸,那么會(huì)向client端發(fā)送一個(gè)keepalivepacket,此時(shí)client端有三種反應(yīng):
1、client端連接正常,返回一個(gè)ACK.server端收到ACK后重置計(jì)時(shí)器,在2小時(shí)后在發(fā)送探測(cè).如果2小時(shí)內(nèi)連接上有數(shù)據(jù)傳輸,那么在該時(shí)間的基礎(chǔ)上向后推延2小時(shí)發(fā)送探測(cè)包;
2、客戶端異常關(guān)閉,或網(wǎng)絡(luò)斷開。client無(wú)響應(yīng),server收不到ACK,在一定時(shí)間(/proc/sys/net/ipv4/tcp_keepalive_intvl75 即75秒)后重發(fā)keepalive packet, 并且重發(fā)一定次數(shù)(/proc/sys/net/ipv4/tcp_keepalive_probes9 即9次);
3、客戶端曾經(jīng)崩潰,但已經(jīng)重啟.server收到的探測(cè)響應(yīng)是一個(gè)復(fù)位,server端終止連接。
修改三個(gè)參數(shù)的系統(tǒng)默認(rèn)值
臨時(shí)方法:向三個(gè)文件中直接寫入?yún)?shù),系統(tǒng)重啟需要重新設(shè)置;
臨時(shí)方法:sysctl -w net.ipv4.tcp_keepalive_intvl=20
全局設(shè)置:可更改/etc/sysctl.conf,加上:
net.ipv4.tcp_keepalive_intvl = 20
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_time = 60
有關(guān)SO_KEEPALIVE的三個(gè)參數(shù)詳細(xì)解釋如下:
tcp_keepalive_intvl,?;钐綔y(cè)消息的發(fā)送頻率。默認(rèn)值為75s。
發(fā)送頻率tcp_keepalive_intvl乘以發(fā)送次數(shù)tcp_keepalive_probes,就得到了從開始探測(cè)直到放棄探測(cè)確定連接斷開的時(shí)間,大約為11min。
tcp_keepalive_probes,TCP發(fā)送?;钐綔y(cè)消息以確定連接是否已斷開的次數(shù)。默認(rèn)值為9(次)。
注意:只有設(shè)置了SO_KEEPALIVE套接口選項(xiàng)后才會(huì)發(fā)送保活探測(cè)消息。tcp_keepalive_time,在TCP保活打開的情況下,最后一次數(shù)據(jù)交換到TCP發(fā)送第一個(gè)保活探測(cè)消息的時(shí)間,即允許的持續(xù)空閑時(shí)間。默認(rèn)值為7200s(2h)。
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
int keepAlive = 1; // 開啟keepalive屬性
int keepIdle = 60; // 如該連接在60秒內(nèi)沒有任何數(shù)據(jù)往來(lái),則進(jìn)行探測(cè)
int keepInterval = 5; // 探測(cè)時(shí)發(fā)包的時(shí)間間隔為5 秒
int keepCount = 3; // 探測(cè)嘗試的次數(shù).如果第1次探測(cè)包就收到響應(yīng)了,則后2次的不再發(fā).
setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE,(void*)&keepAlive, sizeof(keepAlive));
setsockopt(rs, SOL_TCP,TCP_KEEPIDLE,(void*)&keepIdle, sizeof(keepIdle));
setsockopt(rs, SOL_TCP, TCP_KEEPINTVL,(void*)&keepInterval, sizeof(keepInterval));
setsockopt(rs, SOL_TCP, TCP_KEEPCNT,(void*)&keepCount, sizeof(keepCount));
?
?
4、??? 時(shí)間等待計(jì)時(shí)器
?
時(shí)間等待計(jì)時(shí)器是在四次握手的時(shí)候使用的。四次握手的簡(jiǎn)單過程是這樣的:假設(shè)客戶端準(zhǔn)備中斷連接,首先向服務(wù)器端發(fā)送一個(gè)FIN的請(qǐng)求關(guān)閉包(FIN=final),然后由established過渡到FIN-WAIT1狀態(tài)。服務(wù)器收到FIN包以后會(huì)發(fā)送一個(gè)ACK,然后自己由established進(jìn)入CLOSE-WAIT。此時(shí)通信進(jìn)入半雙工狀態(tài),即留給服務(wù)器一個(gè)機(jī)會(huì)將剩余數(shù)據(jù)傳遞給客戶端,傳遞完后服務(wù)器發(fā)送一個(gè)FIN+ACK的包,表示我已經(jīng)發(fā)送完數(shù)據(jù)可以斷開連接了,接著便進(jìn)入LAST_ACK階段。客戶端收到以后,發(fā)送一個(gè)ACK表示收到并同意請(qǐng)求,接著由FIN-WAIT2進(jìn)入TIME-WAIT階段。服務(wù)器端收到ACK,結(jié)束連接。此時(shí)(即客戶端發(fā)送完ACK包以后),客戶端還要等待2MSL(MSL=maxinumsegmentlifetime 最長(zhǎng)報(bào)文生存時(shí)間,2MSL就是兩倍MSL)才能真正關(guān)閉連接。
等待2MSL是因?yàn)榭头税l(fā)送的ACK對(duì)方可能沒有收到,1>此時(shí)服務(wù)端就要重FIN+ACK包,所以2MSL是從客服端發(fā)ACK對(duì)方?jīng)]有到然后服務(wù)端重發(fā)FIN+ACK的最長(zhǎng)時(shí)間,等2MSL就是為了保證對(duì)方已經(jīng)收到ACK包了。若不然,客戶端提早斷開的話服務(wù)器端一直重發(fā)FIN+ACK,永遠(yuǎn)無(wú)法進(jìn)入CLOSE狀態(tài)。
時(shí)間等待計(jì)時(shí)器就是用來(lái)記2MSL這個(gè)時(shí)間的,當(dāng)計(jì)時(shí)器到了2MSL以后,客服端才能斷開連接。2>能夠保證之前某些在網(wǎng)絡(luò)中滯留很久的發(fā)給服務(wù)器的報(bào)文不會(huì)在本次連接連接關(guān)閉后再去騷擾服務(wù)器。 值得注意的是:最后兩次揮手期間,啟動(dòng)了兩種計(jì)時(shí)器,服務(wù)器向客戶端發(fā)送FIN后啟動(dòng)重傳計(jì)時(shí)器,客戶端收到FIN后,向服務(wù)器發(fā)送ACK,同時(shí)啟動(dòng)Time-Wait計(jì)時(shí)器(時(shí)間長(zhǎng)度為2MSL) 。
?
總結(jié)
以上是生活随笔為你收集整理的网络:TCP维护安全可靠机制提供的定时器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ascii码与hex转换c语言,ASCI
- 下一篇: 大数据Re1