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