網絡編程中的TCP——TCP的連接的建立、關閉、狀態轉移
TCP連接的建立和關閉
wireshark捕獲數據:
TCP三次握手+四次揮手的時序圖:
三次握手:
- 報文段1包含
SYN
標志,這是一個同步報文段,表示發起連接請求,包含自己起始的序號值0;- 報文段2是服務端同意建立連接,發送了自己的起始序號并對第一個報文進行了確認;
- 報文3是對服務端第二個報文的確認;
四次揮手:
- 報文14:由客戶端發起了關閉連接的請求,帶有
FIN
標志位,以及此時的序號和對服務器上一個報文的確認;- 報文15:服務器確認了客戶端的關閉請求,此時進入半關閉狀態;
- 報文16:服務器發出斷開連接請求,開始等待客戶端最后一個確認;
- 報文17:客戶端進行最后的確認;
半關閉狀態
TCP是全雙工的,所以允許兩個方向的數據傳輸單獨關閉。也即是通信的一端可以發送結束報文給對方,告知對方本端已完成數據的發送,但是允許繼續接收來自對方的數據,直到對方也發送報文段關閉連接
以上面那個例子來說,客戶端主動發起了關閉請求,在服務器返回確認之后,就進入了半關閉狀態,客戶端不會繼續向服務端發送新的數據,但是還可以接收服務端的數據
TCP狀態轉移
上圖描述了完整的TCP狀態轉移,下面是狀態轉移時序圖:
三次握手建立連接:
- 客戶端和服務器初始都處于
CLOSED
狀態;- 例子中由客戶端發起連接請求
SYN
,發送完后客戶端變成SYN_SENT
狀態;- 服務器開啟之后首先變成
LISTEN
狀態,在接收到客戶端的SYN
后變成SYN_RCVD
狀態;- 服務器發送
SYN+ACK
,客戶端接收到之后,變成ESTABLISHED
狀態,發送最后一個ACK
;- 最后服務器收到
ACK
之后也變成ESTABLISHED
狀態,建立連接完成;四次揮手:
- 例子中由客戶端首先發起關閉連接請求,客戶端發送完
FIN
后首先變成FIN_WAIT_1
狀態;- 服務器收到關閉連接的請求之后變成
CLOSE_WAIT
狀態,然后發送ACK
表示同意關閉連接;- 客戶端收到服務器的
ACK
進入半關閉狀態,FIN_WAIT_2
;- 此時客戶端不會繼續發送數據,但如果服務器還有數據,服務器會繼續發送數據;
- 服務器發起關閉請求,進入
LASK_ACK
狀態,表示等待客戶端發送最后一個ACK
;- 客戶端收到
FIN
請求,進入TIME_WAIT
狀態,發送最后一個ACK
;- 服務器在收到最后一個
ACK
后首先進入完全關閉狀態;
TIME_WAIT
- 處于
TIME_WAIT
狀態要等待2 * msl
才能完全關閉,原因如下:
- 可靠的終止TCP連接;
- MSL是報文段在網絡中最大生存時間,2MSL保證網絡上兩個傳輸方向上尚未被接受到、遲到的TCP報文段都已經消失,保證新的連接在這個端口建立起來之后不會收到上一個連接的數據;
TIME_WAIT
是第一個主動發起關閉連接的一端才會有的狀態,如果是服務器先發起關閉連接的請求,在收到對方的關閉請求后也會變成TIME_WAIT
狀態;- 處于
TIEM_WAIT
的這個端口不能立即被用來建立新的連接,要等連接徹底關閉;
- 對于客戶端來說,處于
TIME_WAIT
狀態的端口無法立即重新使用不是什么問題,因為客戶端一般使用系統自動分配的臨時端口號來建立連接,一般不會剛好分配到程序上一次用到的端口;- 但是對于服務器來說,他總是使用一個固定端口。如果服務器程序剛剛關閉后又希望立即重新啟動,就要等待2MSL,避免的方式是可以在創建socket時升值
SO_REUSEADDR
來強制進程可以立即使用處于TIME_WAIT
狀態的端口;