1. 程式人生 > >TCP-三次握手和四次揮手簡單理解

TCP-三次握手和四次揮手簡單理解

# TCP-三次握手和四次揮手簡單理解 > 背景:TCP,即傳輸控制協議,是一種面向連線的可靠的,基於位元組流的傳輸層協議。作用是在不可靠的網際網路絡上提供一個可靠的端到端的位元組流服務,為了準確無誤的將資料送達目的地,TCP協議採納三次握手策略。 ## 一、TCP報文 TCP報文格式圖: ![](https://img2020.cnblogs.com/blog/1878490/202007/1878490-20200729115848653-666985668.jpg) 上圖中的幾個欄位需要重點介紹下: | 欄位 | 介紹 | |----|----| | **序列號seq** | 佔4個位元組,用來標記資料段的順序,TCP把連線中傳送的所有資料位元組都編上一個序列號,第一個序列號由本地隨機產生;給位元組編上序號後,就給每一個報文指派一個序號;序列號seq就是這個報文段中的第一個位元組的資料編號。 | | **確認號ack** | 佔4個位元組,期待收到對方下一個報文段段的一個數據位元組的序號;序列號表示報文段攜帶資料段第一個位元組的編號;而確認號指的是期望接受到下一個位元組的編號;因此當前報文段最後一個位元組的**編號+1即為確認號。** | | **確認ACK** | 佔1位,僅當ACK=1時,確認號欄位才有效。ACK=0時,確認號無效。 | | **同步SYN**| 連線建立時用於同步序號。當SYN=1,ACK=0時表示:這是一個連線請求報文段。若同意連線,則在響應報文段中使得SYN=1,ACK=1。因此,SYN=1表示這是一個連線請求,或連線接受報文。**SYN這個標準位只有在TCP建成連線時才會被置1,握手完成後SYN標誌位被置0。** | | **終止FIN** | 用來釋放一個連線。FIN=1表示:此報文段段傳送方的資料已經發送完畢,並要求釋放運輸連線。 | PS:ACK、SYN和FIN這些大寫的單詞表示標誌位,其值要麼是1,要麼是0;ack、seq小寫的單詞表示序號。 **標誌位:** |欄位|含義| |----|----| |URG|緊急指標是否有效。為1時,表示某一位需要被優先處理。| |ACK|確認號是否有效,一般置為1。| |PSH|接收方應該儘快將這個報文交給應用層。| |RST|重置連線。| |SYN|發起一個新連線。| |FIN|釋放一個連線。| 注意:不要將確認序號ack與標誌位中的ACK搞混了。 ## 二、三次握手(Three-Way Handshake) **原理:** 第一次握手:建立連線是,客戶端傳送syn包(syn=x)到伺服器,並進入SYN_SENT狀態,等待伺服器確認;SYN:同步序列號。 第二次握手:伺服器收到syn包,必須確認客戶的SYN(ack=x+1),同時自己也傳送一個SYN包(syn=y),即SYN+ACK包,此時伺服器進入SYN_RECV狀態。 第三次握手:客戶端收到伺服器的SYN+ACK包,向伺服器傳送確認包ACK(ack=y+1),此包傳送完畢,客戶端和伺服器進入ESTABLISHED(TCP連線成功)狀態,完成三次握手。 ![](https://img2020.cnblogs.com/blog/1878490/202007/1878490-20200729120706270-1229853178.png) **為什麼要三次握手?** 三次握手的最主要目的是「雙方確認自己與對方的傳送與接收是正常的」。 第一次握手:Client什麼都不能確認;Server確認了對方傳送正常。 第二次握手:Client確認了:自己傳送、接收正常,對方傳送、接收正常;Server確認了:自己接受正常,對方傳送正常。 第三次握手:Client確認了:自己傳送、接受正常,對方傳送,接受正常;Server確認了:自己傳送了、接受正常,對方傳送、接受正常。 所以三次握手就能確認雙方收發功能是否正常。 **通俗的說法:** Client:喂!聽的到嗎? Server:可以,我聽的到。 Client:好的,我們都能互相聽的對方的話,可以開始通訊了。 **三次握手為什麼不用兩次,或者四次?** 因為只有三次才最合適,三次通訊是最小值,兩次通訊無法確認雙方收發功能的正常,而四次通訊則顯得有些冗餘。 ## 三、四次揮手(Four-Way Wavehand) **意義:** 所謂四次揮手,即終止TCP連線,就是指斷開一個TCP連線時,需要客戶端和服務的總共傳送4個包以確認連線到斷開。在socket程式設計中,這一過程由客戶端或服務的任意一方執行close來觸發,流程如下圖所示: ![](https://img2020.cnblogs.com/blog/1878490/202007/1878490-20200729115933494-1975686070.png) 由於TCP連線時是全雙工的,因此,每個方向都必須要單獨進行關閉,這一原則是主動方完成資料傳送任務後,傳送一個FIN來終止主動方傳送資料的連線,收到一個FIN只是意味著這一方向上沒有資料流動來,即不會再收到主動方的資料,但是在這個TCP連線上被動方仍然能夠傳送資料,直到被動方也傳送了FIN。首先進行關閉的一方將執行主動關閉,而另一方則執行被動關閉。 **原理:** 第一次揮手:Client傳送一個FIN,用來關閉CIient到Server的資料傳輸,Client進入FIN_WAIT_1狀態。 第二次揮手:Server收到FIN後,傳送一個ACK給Client,確認序號為收到,序號+1(與SYN相同,一個FIN佔用一個序號),Server進入CLOSE_WAIT狀態。 第三次揮手:Server傳送一個FIN,用來關閉Server到Client的資料傳輸,Server進入LAST_ACK狀態。 第四次揮手:Client收到FIN後,Client進入TIME_WAIT狀態,接著傳送一個ACK給Server,確認序號為收到,序號+1,Server進入CLOSED狀態,完成四次揮手。 ![](https://img2020.cnblogs.com/blog/1878490/202007/1878490-20200729115954626-1615666771.jpg) **通俗的說法:** Client:我已經說完了。 Server:我收到了,等等我,我還沒說完。 Server:好了,我也說完了。 Client:好的,那我們通訊結束。 上面是一方主動關閉,另一方被動關閉的情況,實際中還會出現同時發起關閉的情況,如下圖所示: ![](https://img2020.cnblogs.com/blog/1878490/202007/1878490-20200729120010358-792419035.png) **為什麼建立連線是三次握手,而關閉連線卻是四次揮手呢?** 這是因為**服務端在LISTEN狀態下,收到建立連線請求的SYN報文後,把ACK和SYN放在一個報文裡傳送給客戶端。而關閉連線是,當收到對方的FIN報文是,僅僅表示對方不再發送資料了,但是還能接收資料**,已方也未必全部資料都發送給對方了,所以已方可以立即close,也可以傳送一些資料給對方後,再發送FIN報文給對方來表示同意現在關閉連線,因此,已方ACK和FIN一般都會分開發送。