您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“為什么TCP建連接要3次,斷連接卻要4次”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
大家好,今天聊聊傳輸層通信協(xié)議TCP的經(jīng)典問題:建連接與斷連接。
網(wǎng)絡(luò)上的傳輸是沒有連接的,包括TCP也是一樣的。
而TCP所謂的“連接”,其實(shí)只不過是在通訊的雙方維護(hù)一個“連接狀態(tài)”,讓它看上去好像有連接一樣。所以,TCP的狀態(tài)變換是非常重要的。
很多人會問,為什么建鏈接要3次握手,斷鏈接需要4次揮手?
對于建鏈接的3次握手,主要是要初始化Sequence Number 的初始值。通信的雙方要互相通知對方自己的初始化的Sequence Number(縮寫為ISN:Inital Sequence Number)——所以叫SYN,全稱Synchronize Sequence Numbers。也就上圖中的 x 和 y。這個號要作為以后的數(shù)據(jù)通信的序號,以保證應(yīng)用層接收到的數(shù)據(jù)不會因?yàn)榫W(wǎng)絡(luò)上的傳輸?shù)膯栴}而亂序(TCP會用這個序號來拼接數(shù)據(jù))。
對于4次揮手,其實(shí)你仔細(xì)看是2次,因?yàn)門CP是全雙工的,所以,發(fā)送方和接收方都需要Fin和Ack。只不過,有一方是被動的,所以看上去就成了所謂的4次揮手。如果兩邊同時斷連接,那就會就進(jìn)入到CLOSING狀態(tài),然后到達(dá)TIME_WAIT狀態(tài)。下圖是雙方同時斷連接的示意圖(你同樣可以對照著TCP狀態(tài)機(jī)看):
另外,有幾個事情需要注意一下:
關(guān)于建連接時SYN超時。試想一下,如果server端接到了clien發(fā)的SYN后回了SYN-ACK后client掉線了,server端沒有收到client回來的ACK,那么,這個連接處于一個中間狀態(tài),即沒成功,也沒失敗。于是,server端如果在一定時間內(nèi)沒有收到的TCP會重發(fā)SYN-ACK。在Linux下,默認(rèn)重試次數(shù)為5次,重試的間隔時間從1s開始每次都翻售,5次的重試時間間隔為1s, 2s, 4s, 8s, 16s,總共31s,第5次發(fā)出后還要等32s都知道第5次也超時了,所以,總共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 2^6 -1 = 63s,TCP才會把斷開這個連接。
關(guān)于SYN Flood攻擊。一些惡意的人就為此制造了SYN Flood攻擊——給服務(wù)器發(fā)了一個SYN后,就下線了,于是服務(wù)器需要默認(rèn)等63s才會斷開連接,這樣,攻擊者就可以把服務(wù)器的syn連接的隊(duì)列耗盡,讓正常的連接請求不能處理。于是,Linux下給了一個叫tcp_syncookies的參數(shù)來應(yīng)對這個事——當(dāng)SYN隊(duì)列滿了后,TCP會通過源地址端口、目標(biāo)地址端口和時間戳打造出一個特別的Sequence Number發(fā)回去(又叫cookie),如果是攻擊者則不會有響應(yīng),如果是正常連接,則會把這個 SYN Cookie發(fā)回來,然后服務(wù)端可以通過cookie建連接(即使你不在SYN隊(duì)列中)。請注意,請先千萬別用tcp_syncookies來處理正常的大負(fù)載的連接的情況。因?yàn)?,synccookies是妥協(xié)版的TCP協(xié)議,并不嚴(yán)謹(jǐn)。對于正常的請求,你應(yīng)該調(diào)整三個TCP參數(shù)可供你選擇,第一個是:tcp_synack_retries 可以用他來減少重試次數(shù);第二個是:tcp_max_syn_backlog,可以增大SYN連接數(shù);第三個是:tcp_abort_on_overflow 處理不過來干脆就直接拒絕連接了。
關(guān)于ISN的初始化。ISN是不能hard code的,不然會出問題的——比如:如果連接建好后始終用1來做ISN,如果client發(fā)了30個segment過去,但是網(wǎng)絡(luò)斷了,于是 client重連,又用了1做ISN,但是之前連接的那些包到了,于是就被當(dāng)成了新連接的包,此時,client的Sequence Number 可能是3,而Server端認(rèn)為client端的這個號是30了。全亂了。RFC793中說,ISN會和一個假的時鐘綁在一起,這個時鐘會在每4微秒對ISN做加一操作,直到超過2^32,又從0開始。這樣,一個ISN的周期大約是4.55個小時。因?yàn)?,我們假設(shè)我們的TCP Segment在網(wǎng)絡(luò)上的存活時間不會超過Maximum Segment Lifetime(縮寫為MSL – Wikipedia語條),所以,只要MSL的值小于4.55小時,那么,我們就不會重用到ISN。
關(guān)于 MSL 和 TIME_WAIT。通過上面的ISN的描述,相信你也知道MSL是怎么來的了。我們注意到,在TCP的狀態(tài)圖中,從TIME_WAIT狀態(tài)到CLOSED狀態(tài),有一個超時設(shè)置,這個超時設(shè)置是 2*MSL(RFC793定義了MSL為2分鐘,Linux設(shè)置成了30s)為什么要這有TIME_WAIT?為什么不直接給轉(zhuǎn)成CLOSED狀態(tài)呢?主要有兩個原因:1)TIME_WAIT確保有足夠的時間讓對端收到了ACK,如果被動關(guān)閉的那方?jīng)]有收到Ack,就會觸發(fā)被動端重發(fā)Fin,一來一去正好2個MSL,2)有足夠的時間讓這個連接不會跟后面的連接混在一起(你要知道,有些自做主張的路由器會緩存IP數(shù)據(jù)包,如果連接被重用了,那么這些延遲收到的包就有可能會跟新連接混在一起)。
關(guān)于TIME_WAIT數(shù)量太多。從上面的描述我們可以知道,TIME_WAIT是個很重要的狀態(tài),但是如果在大并發(fā)的短鏈接下,TIME_WAIT 就會太多,這也會消耗很多系統(tǒng)資源。只要搜一下,你就會發(fā)現(xiàn),十有八九的處理方式都是教你設(shè)置兩個參數(shù),一個叫tcp_tw_reuse,另一個叫tcp_tw_recycle的參數(shù),這兩個參數(shù)默認(rèn)值都是被關(guān)閉的,后者recyle比前者resue更為激進(jìn),resue要溫柔一些。另外,如果使用tcp_tw_reuse,必需設(shè)置tcp_timestamps=1,否則無效。這里,你一定要注意,打開這兩個參數(shù)會有比較大的坑——可能會讓TCP連接出一些詭異的問題(因?yàn)槿缟鲜鲆粯?,如果不等待超時重用連接的話,新的連接可能會建不上。正如官方文檔上說的一樣“It should not be changed without advice/request of technical experts”)。
“為什么TCP建連接要3次,斷連接卻要4次”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。