超詳細且易於理解的三次握手四次揮手過程圖解
## 底層流程圖:
SYN: 表示連線請求 ACK: 表示確認 FIN: 表示關閉連線 seq:表示報文序號 ack: 表示確認序號
## 詳細圖解:
> **圖解流程說明如下:**
## 通訊前:3次握手
**3次握手:呼叫connect 雙方都在準備資源(目的)**
第一次握手:Client將標誌位SYN置為1,隨機產生一個值seq=J,並將該資料包傳送給Server,Client進入SYN_SENT狀態,等待Server確認。
第二次握手:Server收到資料包後由標誌位SYN=1知道Client請求建立連線,Server將標誌位SYN和ACK都置為1,ack (number )=J+1,隨機產生一個值seq=K,並將該資料包傳送給Client以確認連線請求,Server進入SYN_RCVD狀態。
第三次握手:Client收到確認後,檢查ack是否為J+1,ACK是否為1,如果正確則將標誌位ACK置為1,ack=K+1,並將該資料包傳送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連線建立成功,Client和Server進入ESTABLISHED狀態,完成三次握手,隨後Client與Server之間可以開始傳輸資料了。
## 關閉時:4次揮手
**4次揮手--讓雙方都把資源給釋放了(目的)**
**第一次揮手:Client傳送一個FIN,用來關閉Client到Server的資料傳送。**
解析:客戶端呼叫close()-關閉傳送(這時作業系統會把包發給伺服器),即客戶端告訴伺服器不會再給伺服器傳送任何資料,即應用程式不會發,不是作業系統不發
**第二次揮手:Server收到FIN後,傳送一個ACK給Client,確認序號為收到序號+1。**
解析:伺服器會告訴客戶端,伺服器收到資料了(即傳送的通道關閉了)
**第三次揮手:Server傳送一個FIN,用來關閉Server到Client的資料傳送。**
解析:(還剩收資料的通道沒關閉),伺服器的作業系統收到你不發的訊號時,會告訴你的應用程式說:客戶端不會再發資訊過來了,recv_date = new_socket.recv()-(一般應用程式都會阻塞在這裡)-->應用程式recv沒有收到資料後會解堵塞,沒有收到資料就呼叫執行new_socket_close(),即伺服器告訴客戶端我也不給你發資料了(即呼叫close),對於客戶端來說,就是關閉接收的功能(看圖片if...else處)
(藍色的第三個箭頭,是伺服器呼叫close時才會有,如果沒有呼叫close,這個箭頭是不會發過去的,而第二個箭頭是給客戶端回覆我收到你的資料包了,功能不一樣,所以兩個箭頭不能合在一起)
**第四次揮手:Client收到FIN後,接著傳送一個ACK給Server,確認序號為收到序號+1。**
解析:收到關閉的資料要求(即第4 個箭頭)
Close一般是客戶端先呼叫關閉,因為TCP為保證資料可靠信,收到一個數據,就要回復應答一下
## 問答題:
**問:最後一次揮手(即藍色的最後一次箭頭),即客戶端回覆伺服器,那客戶端怎麼知道伺服器有沒有收到呢?**
**答:**
1.(客戶端)誰先呼叫最後一次close,(客戶端)誰就在那等待一段時間,即超時時間,如果沒有收到客戶端的回覆,伺服器過一段時間還會再發一次包過來。
2.(沒有收到最後一次揮手情況)假如伺服器因為特殊原因沒有收到客戶端傳送過來的確認包。(前提不能釋放資源)為了保證伺服器能收到客戶端的確認包,客戶端會在這等待一段時間(等待2倍的2MSL,2-5分鐘左右),
3.(客戶端)先呼叫第一次close,誰就要發最後一次揮手,(客戶端)誰的資源就會在你的電腦上保留2分鐘,這段期間資源不能被釋放,即你的埠不能被重複使用
**問:埠被佔用的解決辦法**
假如是伺服器先調的用第一次close,伺服器就要等待2分鐘,等待期間不能重新繫結同一個埠(除非換埠),如果程式退出在執行,埠就會被佔用(除非換埠執行或者用下面的解決辦法)
**答:**
解決辦法: 設定當伺服器先close 即伺服器端4次揮手之後資源能夠立即釋放,這樣就保證了,下次執行程式時 可以立即繫結7788埠(即重複使用原埠)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
**問:客戶端呼叫close,為什麼沒有出現埠被佔用的情況**
**答:**因為客戶端的埠是沒有繫結的,伺服器的埠是綁定了的,客戶端的埠是隨機的。
**補充知識:**
socket套接字是全雙工的,有2個通道,一個是收資料,一個是發資料,即同時可以收發資料,一點影響都沒有,通過多工程序執行緒,實現同一個套接字的收發資料