一、整理文章起因
工作中一次和其他業務對接接口,在使用過程中出現了我這邊請求對方接口,而對方說沒有收到我的請求,並且該現象還在持續發生,於是我通過tcpdump進行抓包分析,抓包結果如下:
這次的抓包和標準的四次揮手斷開連接有點區別,想着很多時候現在面試一般都會問這些基礎的協議相關內容,三次握手四次斷開連接,TCP,UDP等,所以也想通過這次複習,把很多遺漏地方補充一下
二、TCP報文格式
對上圖重要字段說明:
Source Port: 源端口,16位
Destination Port:目的端口16位
Sequence Number:序列號,32位
Acknowledgment Number:確認序號,32位
Control Bits:
URG: 緊急指針有效
ACK: 確認序號有效
PSH: Push Function
RST: 復位TCP連接
SYN: 發起一個新連接
FIN: 沒有更多的數據發送 ,釋放一個tcp連接
注意:不要把確認序號和標誌位中的ACK弄混了,Ack確認號是對發起方的Seq+1
關於TCP連接過程中不同連接狀態的說明:
- LISTEN:偵聽來自遠方的TCP端口的連接請求.
- SYN-SENT:在發送連接請求後等待匹配的連接請求
- SYN-RECEIVED:在收到和發送一個連接請求後等待對方對連接請求的確認
- ESTABLISHED:代表一個打開的連接,可以接收數據
- FIN-WAIT-1:等待遠程TCP連接中斷請求,或先前的連接中斷請求的確認
- FIN-WAIT-2:從遠程TCP等待連接中斷請求
- CLOSE-WAIT:等待從本地用戶發來的連接中斷請求
- CLOSING:等待遠程TCP對連接中斷的確認
- LAST-ACK:等待原來的發向遠程TCP的連接中斷請求的確認
- TIME-WAIT:等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認
- CLOSED:沒有任何連接狀態
爲了方便理解,寫一個一個socket服務端和客戶端,抓包分析內容,來看一個標準的tcp三次握手和四次揮手
服務端代碼:
import socket,os server = socket.socket() server.bind(('0.0.0.0',6666)) server.listen() while True: conn,addr = server.accept() print("一個新的連接:",addr) try: while True: print("等待接收") data = conn.recv(1024) if not data: break print("recv data:",data) res = data.decode("utf-8").upper() conn.send(res.encode()) print("send done") except Exception as e: print(e) server.close()
客戶端代碼:
import socket,os client = socket.socket() client.connect(('192.168.188.106', 6666)) while True: cmd = input(">>:").strip() client.send(cmd.encode("utf-8")) cmd_res = client.recv(1024) print(cmd_res.decode()) client.close()
抓包對客戶端和服務端的的通信過程進行分析,這是一個非常的標準的三次握手和四次揮手過程:
先看針對上圖中的三次握手:
在看看四次揮手的整理
關於TCP斷開連接的說明
從上面的圖我們可以看到是客戶端主動斷開連接,那麼我們站在客戶端的服務端兩方面
對於客戶端來說:
- 發送FIN告訴服務端要關閉連接,並自己進入FIN-WAIT-1狀態,這個時候就不再處理和發送應用層用戶的數據
- 收到服務端對FIN的ACK後,客戶端進入FIN-WAIT-2狀態,這個時候依然可以接收服務端的數據,如果收不到對方的ACK會再次發送之前包含FIN在內的消息
- 收到服務端發送的FIN之後說明服務端也沒有數據發送並關閉連接了,此時客戶端發送ACK對服務端的FIN進行確認並進入TIME-WAIT,然後等待2MS連接關
對於服務端來說:
- 收到客戶端發送的FIN,發送ACK對這個FIN消息進行確認,並進入到CLOSE-WAIT狀態
- 服務單在發送FIN的之前,如果還有未發送的數據,可以繼續發送,發送FIN之後進入LAST-ACK
- 等待客戶端的ACK消息確認自己的FIN完成關閉,如果客戶端沒有確認會再次發送FIN
小結:
發送FIN之後的一端將不會再發送數據
被斷開的一方收到FIN後,給對方發送ACK表示收到,並自己的狀態更改爲CLOS-WAIT,此時TCP連接處於半關閉狀態。被斷開的一方仍然可以發送數據