建立連接非常重要,它是數(shù)據(jù)正確傳輸?shù)那疤幔粩嚅_連接同樣重要,它讓計算機(jī)釋放不再使用的資源。如果連接不能正常斷開,不僅會造成數(shù)據(jù)傳輸錯誤,還會導(dǎo)致套接字不能關(guān)閉,持續(xù)占用資源,如果并發(fā)量高,服務(wù)器壓力堪憂。
建立連接需要三次握手,斷開連接需要四次握手,可以形象的比喻為下面的對話:
?。跾hake 1] 套接字A:“任務(wù)處理完畢,我希望斷開連接?!?/p>
[Shake 2] 套接字B:“哦,是嗎?請稍等,我準(zhǔn)備一下。”
等待片刻后……
?。跾hake 3] 套接字B:“我準(zhǔn)備好了,可以斷開連接了?!?/p>
[Shake 4] 套接字A:“好的,謝謝合作?!?/p>
下圖演示了客戶端主動斷開連接的場景:
建立連接后,客戶端和服務(wù)器都處于ESTABLISED狀態(tài)。這時,客戶端發(fā)起斷開連接的請求:
1) 客戶端調(diào)用 close() 函數(shù)后,向服務(wù)器發(fā)送 FIN 數(shù)據(jù)包,進(jìn)入FIN_WAIT_1狀態(tài)。FIN 是 Finish 的縮寫,表示完成任務(wù)需要斷開連接。
2) 服務(wù)器收到數(shù)據(jù)包后,檢測到設(shè)置了 FIN 標(biāo)志位,知道要斷開連接,于是向客戶端發(fā)送“確認(rèn)包”,進(jìn)入CLOSE_WAIT狀態(tài)。
注意:服務(wù)器收到請求后并不是立即斷開連接,而是先向客戶端發(fā)送“確認(rèn)包”,告訴它我知道了,我需要準(zhǔn)備一下才能斷開連接。
3) 客戶端收到“確認(rèn)包”后進(jìn)入FIN_WAIT_2狀態(tài),等待服務(wù)器準(zhǔn)備完畢后再次發(fā)送數(shù)據(jù)包。
4) 等待片刻后,服務(wù)器準(zhǔn)備完畢,可以斷開連接,于是再主動向客戶端發(fā)送 FIN 包,告訴它我準(zhǔn)備好了,斷開連接吧。然后進(jìn)入LAST_ACK狀態(tài)。
5) 客戶端收到服務(wù)器的 FIN 包后,再向服務(wù)器發(fā)送 ACK 包,告訴它你斷開連接吧。然后進(jìn)入TIME_WAIT狀態(tài)。
6) 服務(wù)器收到客戶端的 ACK 包后,就斷開連接,關(guān)閉套接字,進(jìn)入CLOSED狀態(tài)。
TCP建立過程(三次握手)
所謂三次握手(Three-Way Handshake)即建立TCP連接,就是指建立一個TCP連接時,需要客戶端和服務(wù)端總共發(fā)送3個包以確認(rèn)連接的建立。
?。?)第一次握手:Client將標(biāo)志位SYN置為1,隨機(jī)產(chǎn)生一個值seq=J,并將該數(shù)據(jù)包發(fā)送給Server,Client進(jìn)入SYN_SENT狀態(tài),等待Server確認(rèn)。
?。?)第二次握手:Server收到數(shù)據(jù)包后由標(biāo)志位SYN=1知道Client請求建立連接,Server將標(biāo)志位SYN和ACK都置為1,ack=J+1,隨機(jī)產(chǎn)生一個值seq=K,并將該數(shù)據(jù)包發(fā)送給Client以確認(rèn)連接請求,Server進(jìn)入SYN_RCVD狀態(tài)。
?。?)第三次握手:Client收到確認(rèn)后,檢查ack是否為J+1,ACK是否為1,如果正確則將標(biāo)志位ACK置為1,ack=K+1,并將該數(shù)據(jù)包發(fā)送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連接建立成功,Client和Server進(jìn)入ESTABLISHED狀態(tài),完成三次握手,隨后Client與Server之間可以開始傳輸數(shù)據(jù)了。
注意:三次握手的序列號和確認(rèn)號,如果用(序列號,確認(rèn)號)表示一次握手,則三次握手的過程序列號和確認(rèn)號如下:
1) 第1步:客戶端向服務(wù)器發(fā)送一個同步數(shù)據(jù)包請求建立連接,該數(shù)據(jù)包中,初始序列號(ISN)是客戶端隨機(jī)產(chǎn)生的一個值,確認(rèn)號是0;
2) 第2步:服務(wù)器收到這個同步請求數(shù)據(jù)包后,會對客戶端進(jìn)行一個同步確認(rèn)。這個數(shù)據(jù)包中,序列號(ISN)是服務(wù)器隨機(jī)產(chǎn)生的一個值,確認(rèn)號是客戶端的初始序列號+1;
3) 第3步:客戶端收到這個同步確認(rèn)數(shù)據(jù)包后,再對服務(wù)器進(jìn)行一個確認(rèn)。該數(shù)據(jù)包中,序列號是上一個同步請求數(shù)據(jù)包中的確認(rèn)號值,確認(rèn)號是服務(wù)器的初始序列號+1。
1、(X,0)
2、(Y,X+1)
3、(X+1,Y+1)
? TCP斷開連接過程(四次揮手)
【注意】中斷連接端可以是Client端,也可以是Server端。
假設(shè)Client端發(fā)起中斷連接請求,也就是發(fā)送FIN報文。Server端接到FIN報文后,意思是說“我Client端沒有數(shù)據(jù)要發(fā)給你了”,但是如果你還有數(shù)據(jù)沒有發(fā)送完成,則不必急著關(guān)閉Socket,可以繼續(xù)發(fā)送數(shù)據(jù)。所以你先發(fā)送ACK,“告訴Client端,你的請求我收到了,但是我還沒準(zhǔn)備好,請繼續(xù)你等我的消息”。這個時候Client端就進(jìn)入FIN_WAIT狀態(tài),繼續(xù)等待Server端的FIN報文。當(dāng)Server端確定數(shù)據(jù)已發(fā)送完成,則向Client端發(fā)送FIN報文,“告訴Client端,好了,我這邊數(shù)據(jù)發(fā)完了,準(zhǔn)備好關(guān)閉連接了”。Client端收到FIN報文后,“就知道可以關(guān)閉連接了,但是他還是不相信網(wǎng)絡(luò),怕Server端不知道要關(guān)閉,所以發(fā)送ACK后進(jìn)入TIME_WAIT狀態(tài),如果Server端沒有收到ACK則可以重傳。“,Server端收到ACK后,”就知道可以斷開連接了“。Client端等待了2MSL后依然沒有收到回復(fù),則證明Server端已正常關(guān)閉,那好,我Client端也可以關(guān)閉連接了。Ok,TCP連接就這樣關(guān)閉了!
由于TCP連接時全雙工的,因此,每個方向都必須要單獨(dú)進(jìn)行關(guān)閉,這一原則是當(dāng)一方完成數(shù)據(jù)發(fā)送任務(wù)后,發(fā)送一個FIN來終止這一方向的連接,收到一個FIN只是意味著這一方向上沒有數(shù)據(jù)流動了,即不會再收到數(shù)據(jù)了,但是在這個TCP連接上仍然能夠發(fā)送數(shù)據(jù),直到這一方向也發(fā)送了FIN。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動關(guān)閉,而另一方則執(zhí)行被動關(guān)閉,上圖描述的即是如此。
?。?)第一次揮手:Client發(fā)送一個FIN,用來關(guān)閉Client到Server的數(shù)據(jù)傳送,Client進(jìn)入FIN_WAIT_1狀態(tài)。
?。?)第二次揮手:Server收到FIN后,發(fā)送一個ACK給Client,確認(rèn)序號為收到序號+1(與SYN相同,一個FIN占用一個序號),Server進(jìn)入CLOSE_WAIT狀態(tài)。
(3)第三次揮手:Server發(fā)送一個FIN,用來關(guān)閉Server到Client的數(shù)據(jù)傳送,Server進(jìn)入LAST_ACK狀態(tài)。
(4)第四次揮手:Client收到FIN后,Client進(jìn)入TIME_WAIT狀態(tài),接著發(fā)送一個ACK給Server,確認(rèn)序號為收到序號+1,Server進(jìn)入CLOSED狀態(tài),完成四次揮手。
四次揮手的序列號和確認(rèn)號
?。╱,0)
(v,u+1)
(w,u+1)
?。╱+1,w+1)
上面是一方主動關(guān)閉,另一方被動關(guān)閉的情況,實際中還會出現(xiàn)同時發(fā)起主動關(guān)閉的情況,具體流程如下圖:
【問題1】為什么連接的時候是三次握手,關(guān)閉的時候卻是四次握手?
答:因為當(dāng)Server端收到Client端的SYN連接請求報文后,可以直接發(fā)送SYN+ACK報文。其中ACK報文是用來應(yīng)答的,SYN報文是用來同步的。但是關(guān)閉連接時,當(dāng)Server端收到FIN報文時,很可能并不會立即關(guān)閉SOCKET,所以只能先回復(fù)一個ACK報文,告訴Client端,”你發(fā)的FIN報文我收到了“。只有等到我Server端所有的報文都發(fā)送完了,我才能發(fā)送FIN報文,因此不能一起發(fā)送。故需要四步握手。
【問題2】為什么TIME_WAIT狀態(tài)需要經(jīng)過2MSL(最大報文段生存時間)才能返回到CLOSE狀態(tài)?
答:雖然按道理,四個報文都發(fā)送完畢,我們可以直接進(jìn)入CLOSE狀態(tài)了,但是我們必須假象網(wǎng)絡(luò)是不可靠的,有可以最后一個ACK丟失。所以TIME_WAIT狀態(tài)就是用來重發(fā)可能丟失的ACK報文。
為什么是2MSL,主要是為了考慮到如果最后一個ACK丟失,服務(wù)端會重新發(fā)FIN,客戶端等待2MSL,才能接收到服務(wù)端重新發(fā)送的FIN報文。
【問題3】RST的作用
RST表示復(fù)位,用來異常的關(guān)閉連接,在TCP的設(shè)計中它是不可或缺的。就像上面說的一樣,發(fā)送RST包關(guān)閉連接時,不必等緩沖區(qū)的包都發(fā)出去(不像上面的FIN包),直接就丟棄緩存區(qū)的包發(fā)送RST包。而接收端收到RST包后,也不必發(fā)送ACK包來確認(rèn)。
TCP處理程序會在自己認(rèn)為的異常時刻發(fā)送RST包。例如,A向B發(fā)起連接,但B之上并未監(jiān)聽相應(yīng)的端口,這時B操作系統(tǒng)上的TCP處理程序會發(fā)RST包。
又比如,AB正常建立連接了,正在通訊時,A向B發(fā)送了FIN包要求關(guān)連接,B發(fā)送ACK后,網(wǎng)斷了,A通過若干原因放棄了這個連接(例如進(jìn)程重啟)。網(wǎng)通了后,B又開始發(fā)數(shù)據(jù)包,A收到后表示壓力很大,不知道這野連接哪來的,就發(fā)了個RST包強(qiáng)制把連接關(guān)了,B收到后會出現(xiàn)connect reset by peer錯誤。
【問題4】當(dāng)URG=1時
緊急比特URG——當(dāng)URG=1時,表明緊急指針字段有效。它告訴系統(tǒng)此報文段中有緊急數(shù)據(jù),應(yīng)盡快傳送(相當(dāng)于高優(yōu)先級的數(shù)據(jù))。
評論
查看更多