1. 程式人生 > >TCP三次握手&四次揮手

TCP三次握手&四次揮手

## TCP概述 > 網路分為IOS七層協議:物理層、資料鏈路層、網路層、傳輸層、會話層、表現層、應用層 > TCP協議屬於傳輸層的協議 ### TCP資料包結構圖 ![](https://img2020.cnblogs.com/blog/1844597/202103/1844597-20210314103202036-980589272.jpg) 在進行握手時,就依賴著結構中的**序號**和**確認號** ### TCP中的識別符號 **SYN:同步標誌** > 同步序列編號(`Synchronize Sequence Numbers`)欄有效。該標誌僅在三次握手建立TCP連線時有效。它提示TCP連線的服務端檢查序列編號,該序列編號為TCP連線初始端(一般是客戶端)的初始序列編號。在這裡,可以把TCP序列編號看作是一個範圍從0到4,294,967,295的32位計數器。通過TCP連線交換的資料中每一個位元組都經過序列編號。在TCP報頭中的序列編號欄包括了TCP分段中第一個位元組的序列編號 **ACK:確認標誌** > 確認編號(`Acknowledgement Number`)欄有效。大多數情況下該標誌位是置位的。TCP報頭內的確認編號欄內包含的確認編號(w+1,Figure-1)為下一個預期的序列編號,同時提示遠端系統已經成功接收所有資料 **URG:緊急標誌** > 緊急(`The urgent pointer`) 標誌有效,緊急標誌置位 **FIN:結束標誌** > 帶有該標誌置位的資料包用來結束一個TCP會話,但對應埠仍處於開放狀態,準備接收後續資料 > 三次握手`Three-way Handshake` ## 三次握手 > 一個虛擬連線的建立是通過三次握手實現的 ### 示意圖 ![](https://img2020.cnblogs.com/blog/1844597/202103/1844597-20210314103213607-1615622098.png) ### 三次握手流程 1. B的TCP伺服器程序先建立**傳輸模組TCB**,準備接受客戶程序的連線請求。然後伺服器程序就處於`LISTEN`(收聽)狀態,等待客戶的連線請求 2. 第一次握手:A的TCP客戶程序也是首先建立**傳輸控制模組TCB**,然後向B發出連線請求報文段,此時首部中的同部位`SYN = 1`,同時選擇一個初始序號`seq = x`(這個指令的意思就是告訴B客戶機自己的序號是多少,要接著這個序號傳送資料報)。TCP規定,SYN報文段(即`SYN = 1`的報文段)不能攜帶資料,但是要消耗一個需要。此時TCP客戶程序進入`SYN-SENT`(同步已傳送)狀態 3. 第二次握手:B收到連續請求報文段後,如同意建立連線,則向A傳送確認。在確認報文段中應把`SYN`位和`ACK`位都置為1,確認號是`ack = x + 1`,同時自己也為自己選擇一個初始序號 `seq = y`。(注意:這個報文段也不能攜帶資料,但同樣需要消耗掉一個序號)。這時TCP伺服器程序進入`SYN-REVD`(同步收到)狀態 4. 第三次握手:TCP客戶程序收到B的確認後,還要向B給出確認。確認報文段的ACK置1,確認號`ack = y + 1`,而自己的序號`seq = x + 1`。TCP的標準規定,ACK報文段可以攜帶資料。但如果不攜帶資料則不消耗序號,在這種情況下,下一個資料報文段的序號仍是 `seq = x + 1`。這時,TCP連線建立,A進入`ESTABLISHED`(已建立連線)狀態,當B收到A的確認訊息後,也進入`ESTABLISHED`狀態 > 注:最後一次握手在預設不攜帶資料的情況下,由於SYN不是1,是不消耗序列號的。所以三次握手結束後,客戶端下一個傳送的報文中`seq`依舊是`x + 1` ### 為什麼需要三次握手,而非兩次? > - 為了實現可靠資料傳輸, TCP 協議的通訊雙方, 都必須維護一個序列號, 以標識傳送出去的資料包中, 哪些是已經被對方收到的。 三次握手的過程即是通訊雙方相互告知序列號起始值, 並確認對方已經收到了序列號起始值的必經步驟 > - 如果只是兩次握手, 至多隻有連線發起方的起始序列號能被確認, 另一方選擇的序列號則得不到確認 ## 四次揮手 > 一個虛擬連線的斷開是通過四次揮手實現的 ### 示意圖: ![](https://img2020.cnblogs.com/blog/1844597/202103/1844597-20210314103221594-576314168.png) ### 四次揮手流程: 1. 第一次揮手:A資料傳輸關閉,需要斷開連線,A應用程序向其TCP發出連線釋放報文段(`FIN = 1, seq = u`),並停止在傳送資料,主動關閉TCP連線,進入FIN-WAIT-1狀態,等待B的確認 2. 第二次揮手:B收到連線釋放報文後即發出確認報文段(`ACK = 1`,確認號`ack = u + 1`,序列號`seq = v`),B進入CLOSE-WAIT關閉等待狀態,此時的TCP處於半關閉狀態,A到B的連線釋放。而A收到B的確認後,進入FIN-WAIT-2狀態,等待B發出的連線釋放報文段 3. 第三次揮手:當B資料傳輸完畢,B發出連線釋放報文段(`FIN = 1`, `ACK = 1`,序號`seq = u + 1`,確認號 `ack = u + 1`),B進入LAST-ACK(最後確認)狀態,等待A的最後確認 4. 第四次揮手:A收到B的連線釋放報文段後,對此發出確認報文段(`ACK = 1`,`seq = u + 1`,`ack = w + 1`),A進入TIME-WAIT(時間等待)狀態,此時TCP未釋放掉,需要經過時間等待計時器設定的時間2MSL後,A才進入CLOSE狀態 ### 為什麼A在TIME-WAIT狀態必須等待2MSL(最大報文生存時間)的時間? 為了保證A傳送的最後一個ACK報文段能夠到達B,保證A、B正常進入CLOSED狀態 > 這個ACK報文段有可能丟失,使得處於LAST-ACK狀態的B收不到對已傳送的FIN+ACK報文段的確認,B超時重傳FIN+ACK報文段,A能2MSL時間內收到這個重傳的FIN+ACK報文段,接著A重傳一次確認,同時重啟2MSL計數器,2MSL時間後A和B進入CLOSE狀態,如果A在TIME-WAIT狀態時接收到B的FIN+ACK報文段之後向B發出確認報文段,而不再確認B是否收到立即進入CLOSED狀態,如若B並沒有正常收到A 的確認報文段,則B無法正正常進入到CLOSED狀態 >