4-5:TCP协议之连接管理机制(三次握手、四次挥手详解)
文章目錄
- 一:TCP三次握手過程和狀態變遷
- (1)三次握手過程和狀態變遷過程詳解
- (2)為什么必須要三次握手?
- A:只有三次握手才可以阻止重復歷史連接的初始化(主要原因)
- B:同步雙方初始序列號
- C:避免資源浪費
- 二:TCP四次揮手過程和狀態變遷
- (1)四次揮手過程和狀態變遷詳解
- (2)為什么需要四次揮手?
- (3)什么是TIME_WAIT以及為什么TIME_WAIT是2MSL
- A:TIME_WAIT
- B:為什么需要TIME_WAIT
- 三:實踐-理解TIMIE_WAIT狀態
本文大部分內容來自小林coding《圖解網絡》,感謝分享,簡單整理。
一:TCP三次握手過程和狀態變遷
(1)三次握手過程和狀態變遷過程詳解
TCP是面向連接的協議,所以使用TCP前必須先建立連接,而建立連接是通過三次握手完成的。
開始的時候,客戶端和服務端都處于CLOSED狀態。服務器主動監聽某個端口,處于LISTEN狀態
客戶端會隨機初始化序號(client_isn), 將此序號置于TCP首部的【序號】字段中,同時將SYN標志位置為1,表示SYN報文。接著把第一個SYN報文發送給服務端,表示向服務器發起連接,該報文不包含應用層數據,之后客戶端就處于了SYN-SENT狀態
服務端收到客戶端的SYN報文后,服務端也會隨機初始化自己的序號(server_isn),將此序號填入TCP首部的【序號】字段中,其次在TCP首部【確認應答號】填入client_isn+1,接著把SYN和ACK標志位置為1,最后把報文發給客戶端,該報文也不包含應用程序數據。之后服務端處于SYN-RCVD狀態
客戶端受到服務端報文后,還要向服務器回應最后一個應答報文。于是將該應答報文TCP首部ACK標志位置為1,其【確認應答號】字段填入server_isn+1,最后把報文發送給服務端。此次報文可以攜帶客戶服務器的數據,之后客戶端處于ESTABLISHED狀態。服務器在收到客戶端應答報文后,也進入ESTABALISHED狀態
一旦完成三次握手,客戶端就都處于了ESTABALISHED狀態,此時鏈連接建立完成,客戶端和服務端就可以相互發送數據了。
(2)為什么必須要三次握手?
在講述之前,我們需要再次回復是什么是TCP連接:
- 用于保證可靠性和流量控制維護的某些狀態信息,這些信息的組合,包括Socket,序列號和窗口大小稱為連接
A:只有三次握手才可以阻止重復歷史連接的初始化(主要原因)
RFC793指出的TCP連接使用三次握手的主要原因:
Thep principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.
意思是:為了防止舊的重復連接初始化造成混亂
網絡環境錯綜復雜,它并不遵循先發先到的原則,有可能新的數據相比舊的數據會先到目標主機,而三次握手可以避免這種混亂
因此在網絡擁堵的情況下,一個舊的SYN報文比新的SYN早到了服務端,那么此時服務端會返回一個SYN+ACK報文給客戶端,客戶端收到后可以根據自身上下文,判斷這是一個歷史連接,那么客戶端會發送RST給服務端,中止此次連接
相反,如果是兩次握手,就無法判斷是否是歷史連接。三次握手則可以在客戶端準備發送第三次報文時,能夠擁有足夠的上下文判斷當前是否為歷史連接
B:同步雙方初始序列號
TCP協議通信的雙方,都必須維護一個【序列號】,序列號是可靠傳輸的關鍵因素,具體作用
- 接收方可以去除重復數據
- 接收方可以根據數據包的序列號按序接受
- 可以標識發送出去的數據,哪些是已經被對方接收的
所以當客戶端發送攜帶【初始序列號】的SYN報文的時候,需要服務端返回一個ACK應答報文,表示客戶端的SYN報文服務端已經成功接收;而當服務端發送【初始序列號】給客戶端時,依然也要得到客戶端的應答回應。這樣一來一回,才能保證雙方的序列號可以被可靠同步
四次握手其實也能夠可靠的同步初始化序列號,可以把第二步和第三步優化為一步,減少通信次數
前兩次握手只保證了一方的初始序列號可以被對方成功接收,沒有辦法保證雙方的初始初始序列號都能被確認接收
C:避免資源浪費
如果僅有兩次握手,當客戶端的SYN請求在網絡中堵塞時,客戶端沒有接受到ACK,就會觸發重傳,由于沒有三次握手,所以服務端不清楚客戶端是否已經收到了自己發送的建立連接的ACK確認,所以每收到一個SYN就先去建立一個連接
這樣做的后果很麻煩。如果客戶端的SYN堵塞了,重復發送了多次SYN報文,那么服務器在收到SYN后就會建立多個冗余的無效連接,造成資源浪費
同時這也容易受到SYN FIood(SYN洪水攻擊)。
最后,服務器是一對多的,從上面的敘述中可以看出。不論是幾次握手,我們能保證前n?1n-1n?1次是可靠的,但是第n次是誰發誰的,誰就會認為連接建立好了,誰就要承擔連接丟失的后果,所以我們肯定盡可能讓客戶端背鍋,否則服務器會產生大量的廢棄連接
二:TCP四次揮手過程和狀態變遷
TCP斷開連接是通過四次揮手的方式進行的,雙方都可以斷開連接,斷開連接后主機資源將會被釋放
(1)四次揮手過程和狀態變遷詳解
具體過程如下
- 客戶端打算關閉連接,此時會發送一個TCP首部FIN標志位置為1的報文,也即FIN報文,之后客戶端會進行FIN_WAIT_1狀態(應用層close,用戶不可能發送數據)
- 服務端受到該報文后,就像客戶端發送ACK應答報文,接著服務端進入CLOSE_WAIT狀態
- 客戶端收到服務端的ACK應答報文后,進行FIN_WAIT_2狀態
- 等待服務端處理完數據后,就會向客戶端發送FIN報文,之后服務端進行LAST_ACK狀態
- 客戶端再收到服務端的FIN報文后,回應一個ACK應答報文,之后進入TIME_WAIT狀態
- 服務端收到了ACK后,進入CLOSED狀態,至此服務端完成連接關閉
- 客戶端在經過2MSL后,自動進入CLOSED狀態,至此客戶端完成連接的關閉
需要注意,主動關閉連接的才會有TIME_WAIT狀態
(2)為什么需要四次揮手?
首先關閉連接時,客戶端向服務端發送FIN,僅僅表示關閉的是客戶端對服務端的單向信道;服務端收到客戶端的FIN報文時,先回應一個ACK,表示“你先等等,可能還有數據未處理完”,等服務端不再發送數據時,才發送FIN報文給客戶端表示同意現在關閉連接
所以多的那一次一般就是服務端需要等待完成數據的發送和處理,其中的ACK和FIN分開發送了
(3)什么是TIME_WAIT以及為什么TIME_WAIT是2MSL
A:TIME_WAIT
MSL是MaximumMaximumMaximum SegmentSegmentSegment LifetimeLifetimeLifetime的縮寫,意為報文最大生存時間,它是任何報文在網絡上存在的最長時間,超過此時間報文將會被丟棄。
- TCP報文基于IP協議,而且IP頭中有一個TTL字段,是IP數據報文可以經過的最大路由數目,每經過一個處理他的路由器此值就會減1,當此值為0時數據報將會被丟棄,同時發送ICMP報文通知源主機。
TIME_WAIT要等待2倍的MSL是因為網絡中可能存在來自發送方的數據包,當這些發送方的數據報文被接收方處理之后又會向對方發送響應,所以一來一回需要2倍時間
2MSL的時間是從客戶端接收到FIN后發送ACK開始計時的。如果在TIME-WAIT時間內,因為客戶端的ACK沒有傳輸到服務器,客戶端又接收到了服務器重發的FIN報文,那么2MSL會重新計時
Linux系統中一個MSL是30s、所以Linux系統停在TIME_WAIT的時間為60s
其定義在Linux內核代碼里的名稱為TCP_TIMEWAIT_LEN
B:為什么需要TIME_WAIT
1:防止舊連接的數據包
假設TIME_WAIT沒有等待時間或者等待時間過多,會發生什么呢?如下
上圖中,由于關閉連接前SEQ=301的報文被延遲了,如果此時有相同端口的TCP連接被復用后,被延長的SEQ=301抵達了客戶端,那么客戶端有可能會接受這個過期的報文,造成一些嚴重的問題
所以TCP設計了2MSL的時間,足以讓這兩個方向上的數據包都自動丟棄,使原來連接的數據包在網絡中自然消失,再出現的數據包一定是新建立的。
2:保證連接正確關閉
TIME_WAIT的另一個作用就是等待足夠的時間以確保最后的ACK讓被動關閉方接收,從而幫助其正確關閉
還是假設TIME_WAIT沒有等待時間或過短,此時又會造成什么問題呢?如下
可以看出,如果最后一個ACK報文傳輸丟失了,因為沒有TIME_WAIT或時間過短,此時客戶端就會直接進入CLOSE狀態,服務端則會一直保持LASE_ACK狀態。那么此時當客戶端發起建立連接的SYN請求后,服務端就會發送RST給客戶端,連接會被中止。
三:實踐-理解TIMIE_WAIT狀態
如下有一個簡單的http服務器,啟動服務器后綁定8080端口,在正常情況下是可以綁定成功的,服務器開始運行
然后使用瀏覽器訪問該服務器,一般情況下是客戶端主動斷開連接。但是現在我們用Ctrl+C結束服務端程序,然后再次連接時,會發現無法再綁定這個端口。
這是因為,雖然服務端的應用程序終止了,但是TCP協議層的連接并沒有完全斷開,因此不能再次監聽同樣的端口。主動關閉連接的一方,進入TIME_WAIT狀態
可以使用netstat命令查看
其實在服務端的TCP連接沒有完全斷開之前不允許重新監聽,這樣的設計在有些情況下是不合理的。
服務器一般需要處理巨量的客戶端連接(每個連接的生存時間可能很短,但是每秒都有很大數量的客戶端請求),這個時候如果由服務器主動關閉連接,機會產生大量的TIME_WAIT狀態,由于請求量很大,就可能導致TIME_WAIT的連接數很多,每個連接都會占用一個通信五元組(源ip,源端口,目的ip,目的端口,協議)其中服務器的ip和端口和協議是固定的。如果新到來的客戶端連接的ip和端口和TIME_WAIT占用連接重復了,就會出現很多問題
其實使用setsockopt(),其中SO_REUSEADDR為1,可以設置允許創建端口號相同但ip地址不同的多個socket描述符
int opt=1; setsockopt(listenfd,SOL_SOCKET,SO_reuseaddr,&opt,sizeof(opt));在服務器中加入以下代碼
總結
以上是生活随笔為你收集整理的4-5:TCP协议之连接管理机制(三次握手、四次挥手详解)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 七种寻址方式(寄存器相对寻址方式)
- 下一篇: 02 基本概念