昨天騰訊筆試考了四次握手的狀態名詞,雖然對過程有所瞭解,可是沒有總結其中的狀態變化,系統的複習下html
所謂三次握手(Three-way Handshake),是指創建一個 TCP
鏈接時,須要客戶端和服務器總共發送3個包。git
三次握手的目的是鏈接服務器指定端口,創建 TCP
鏈接,並同步鏈接雙方的序列號和確認號,交換 TCP
窗口大小信息。在 socket
編程中,客戶端執行 connect()
時。將觸發三次握手。github
SYN=1, seq=x
):客戶端發送一個 TCP
的 SYN
標誌位置1的包,指明客戶端打算鏈接的服務器的端口,以及初始序號 X,保存在包頭的序列號(Sequence Number)字段裏。
發送完畢後,客戶端進入 SYN_SEND 狀態。編程
SYN=1, ACK=1, seq=y, ACKnum=x+1
):服務器發回確認包(ACK)應答。即 SYN
標誌位和 ACK
標誌位均爲1。服務器端選擇本身 ISN 序列號,放到Seq
域裏,同時將確認序號(Acknowledgement Number)設置爲客戶的 ISN 加1,即X+1。
發送完畢後,服務器端進入 SYN_RCVD 狀態。服務器
ACK=1,ACKnum=y+1
)客戶端再次發送確認包(ACK),SYN
標誌位爲0,ACK
標誌位爲1,而且把服務器發來 ACK
的序號字段+1,放在肯定字段中發送給對方,而且在數據段放寫ISN
發送完畢後,客戶端進入 ESTABLISHED 狀態,當服務器端接收到這個包時,也進入 ESTABLISHED 狀態,TCP
握手結束。網絡
TCP的鏈接的拆除須要發送四個包,所以稱爲四次揮手(Four-way handshake),也叫作改進的三次握手。客戶端或服務器都可主動發起揮手動做,在 socket 編程中,任何一方執行 close() 操做便可產生揮手操做。socket
FIN=1,seq=x
)假設客戶端想要關閉鏈接,客戶端發送一個 FIN
標誌位置爲1的包,表示本身已經沒有數據能夠發送了,可是仍然能夠接受數據。.net
發送完畢後,客戶端進入 FIN_WAIT_1
狀態。code
ACK=1,ACKnum=x+1
)服務器端確認客戶端的 FIN
包,發送一個確認包,代表本身接受到了客戶端關閉鏈接的請求,但尚未準備好關閉鏈接。htm
發送完畢後,服務器端進入 CLOSE_WAIT
狀態,客戶端接收到這個確認包以後,進入 FIN_WAIT_2
狀態,等待服務器端關閉鏈接。
FIN=1,seq=y
)服務器端準備好關閉鏈接時,向客戶端發送結束鏈接請求,FIN
置爲1。
發送完畢後,服務器端進入 LAST_ACK
狀態,等待來自客戶端的最後一個ACK
。
ACK=1,ACKnum=y+1
)客戶端接收到來自服務器端的關閉請求,發送一個確認包,並進入 TIME_WAIT
狀態,等待可能出現的要求重傳的 ACK
包。
服務器端接收到這個確認包以後,關閉鏈接,進入 CLOSED
狀態。
客戶端等待了某個固定時間(兩個最大段生命週期,2MSL,2 Maximum Segment Lifetime)以後,沒有收到服務器端的 ACK
,認爲服務器端已經正常關閉鏈接,因而本身也關閉鏈接,進入 CLOSED
狀態。
【問題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
報文。