TCP是什么?
???????TCP(Transmission Control Protocol)是一種面向連接的、可靠的、基于字節流的傳輸層通信協議。
???????關于TCP具體的知識這兒就不介紹了,下面挑出一些我們需要了解的基本知識進行重溫
TCP頭部
???????上面就是TCP協議頭部的格式,由于它太重要了,是理解其它內容的基礎,下面就將每個字段的信息都詳細的說明一下。
-
源端口號(Source Port)/ 目標端口號(Destination Port):
???????表示發送端端口號和接受端端口號,字段長度均為16位(這也解釋了為什么端口號的范圍是0~65535),源端口號和目標端口號配合上IP首部中的源IP地址和目標IP地址就能唯一地確定一個TCP連接 -
序列號(Sequence Number):
???????字段長度為32位,用來指示發送數據的位置,需要注意的是它不一定從0或1開始,而是在建立連接時由計算機生成的隨機數作為初始值;主要用來解決網絡報亂序的問題 -
確認應答號(Acknowlegdement Number):
???????字段長度為32位,用來指示下一次應該收到的數據的序列號,實際上它代表了已收到確認應答號減一為止的數據。不過,只有當標志位中的ACK標志為1時該確認序列號的字段才有效。主要用來解決丟包問題 -
數據偏移(Data Offset):
???????給出首部的長度,需要這個值是因為選項字段的長度是可變的。這個字段占4位,每一位表示4個字節(即32位)。因此TCP最多有60字節的首部。然而,沒有任選字段,正常的長度是20字節 -
保留(Reserved):
???????該字段主要是為了以后擴展時使用 -
控制位(Control Flag):
-
URG(Urgent Flag):
該位為1時,表示包中有需要緊急處理的數據,用來保證TCP連接不被中斷,對于需要緊急處理的數據,會在后面的緊急指針中再進行解釋 -
ACK(Acknowledgment Flag):
該位為1時,確認應答的字段變為有效。TCP規定除了最初建立連接時的SYN包之外該位必須置為1 -
PSH(Push Flag):
這個標志位表示Push操作。所謂Push操作就是指在數據包到達接收端以后,立即傳送給上層應用協議,而不是在緩沖區中排隊 -
RST(Reset Flag):
該位為1時表示TCP連接中出現異常必須強制斷開連接,用來復位那些產生錯誤的連接,也被用來拒絕錯誤和非法的數據包 -
SYN(Synchronize Flag):
用于建立連接,置1時表示希望建立連接,并在其序列號的字段進行序列號初始值的設定,通常與ACK搭配使用 -
FIN(Finish Flag):
表示數據傳送完成,沒有數據可以傳送了,當通信結束希望斷開連接時,通信雙方的主機之間就可以交換FIN位置為1的TCP段
-
URG(Urgent Flag):
-
窗口大小(Window Size):
???????該字段長為16位,用于通知從相同TCP首部的確認應答號所指位置開始能夠接收的數據大小(8位字節)。TCP不允許發送超過此處所示大小的數據。另外,窗口為0時可用于發送窗口探測,以了解最新的窗口大小,但這個數據必須是1字節
三次握手及四次揮手
接下來就是今天的重頭戲,首先是借由上圖對兩個“手”的過程的流程解讀
三次握手
???????當我們需要通過TCP來傳輸數據時,就必須讓客戶端和服務端建立連接,這就是所謂的“三次握手”
1.第一次握手:建立連接。客戶端發送連接請求報文段,將SYN位置為1,Seq為x;接著客戶端進入SYN_SEND狀態,等待服務端的確認
2.第二次握手:服務端收到客戶端的SYN報文段,需要對這個SYN報文段進行確認,設置Ack為x+1(即Seq+1);同時,自己還要發送SYN請求信息,將SYN位置為1,Seq為y;服務端將上述所有信息放到一個報文段(即SYN+ACK報文段)中,一并發送給客戶端,此時服務器進入SYN_RECV狀態
3.第三次握手:客戶端收到服務器的SYN+ACK報文段后將Ack設為y+1,向服務器發送ACK報文段,這個報文段發送完畢以后,客戶端和服務器端都進入ESTABLISHED狀態,完成TCP三次握手
完成了三次握手,客戶端和服務器端就可以開始愉快地傳送數據啦~
四次揮手
???????那么當數據傳輸完畢后,我們必然會面臨斷開連接的問題,這個時候就需要“四次揮手”出場了~
1.第一次揮手:主機1(客戶端或服務器端均可),設置Seq和Ack,向主機2發送一個FIN報文段;此時,主機1進入FIN_WAIT_1狀態;這表示主機1沒有數據要發送給主機2了
2.第二次揮手:主機2收到了主機1發送的FIN報文段,向主機1回一個ACK報文段;主機1進入FIN_WAIT_2狀態;主機2告訴主機1,我“同意”你的關閉請求,但我可能還有數據需要傳輸,所以不要立即關閉
3.第三次揮手:主機2向主機1發送FIN報文段,表示我這已經準備好了,隨時可以關閉連接了,同時主機2進入LAST_ACK狀態
4.第四次揮手:主機1收到主機2發送的FIN報文段,向主機2發送ACK報文段,然后主機1進入TIME_WAIT狀態;主機2收到主機1的ACK報文段以后,就關閉連接;此時,主機1等待2MSL后依然沒有收到回復,則證明服務端已正常關閉,那么主機1也可以關閉連接了
???????到這里,一個完整的TCP建立連接 => 傳送數據 => 斷開連接的流程就結束了,然后就是處理一些常見的疑問(別稱:面試題)
疑問1:為什么必須是四次揮手呢?把第二次揮手和第三次揮手合為一次不行嗎?
答:關閉連接時,當服務端收到FIN報文時,很可能并不會立即關閉SOCKET(因為此時數據很可能未傳輸完畢),暫且只能先回復一個ACK報文,告訴客戶端,"你發的FIN報文我收到了"。只有等到我服務端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四次揮手。
疑問2:三次握手中最后一次握手不能直接去掉嗎?
答:在謝希仁著《計算機網絡》第四版中講“三次握手”的目的是“為了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤”。什么意思呢?假設我們將其改為兩次握手,那么如果A發出連接請求,但因連接請求報文丟失而未收到確認,于是客戶端再重傳一次連接請求,而后收到確認后建立好了連接,接著該干嘛該干嘛,最后把連接斷開就完事兒了。但是,這時候上一個丟失的報文突然又冒出來傳到服務端去了,服務端接收后返回確認報文,按照我們假設的情況,這時候本不該建立的連接便建立起來了,可客戶端本就無意建立連接,也就不會發送數據給服務端,服務端就一直干等著,浪費資源。
疑問3:為什么TIME_WAIT狀態需要經過2MSL(最大報文段生存時間)才能返回到CLOSED狀態?
答:TIME_WAIT狀態其實是用來重發可能丟失的ACK報文,為啥呢?你想啊,要是最后一次揮手發出去的ACK報文不見了咋辦,這時候服務端就不斷地拋FIN給客戶端,問“我可以結束了呀,你咋不理我了呢”,但客戶端早早地就進入CLOSED態,誰還理你呀~因此需要客戶端設置一個定時器來防止這種窘境的出現,在這段時間里如果你沒重復發送FIN給我,那我就默認你收到我的報文了,于是斷開連接
參考資料(感謝各位前輩大佬):