TCP協議之三次握手與四次揮手


TCP協議是TCP/IP體系中核心一個協議,該協議比起IP協議,ICMP協議,UDP協議都更復雜,因此這篇文章主要分析TCP協議在建立連接和斷開連接的時候,狀態轉移以及報文段的內容。
下面,先放一張TCP的狀態轉移圖:

center

TCP協議之三次握手

三次握手的過程是TCP在客戶端和服務端建立連接的過程。簡單的來說三次握手過程,就是客戶端先發送一個連接請求給服務端,這是第一次握手。服務端接收到客戶端發來的鏈接請求,然后在將確認的消息發給客戶端,這是第二次握手。客戶端對服務端發來的確認消息進行確認,然后將確認的消息發給服務端,這就是三次握手。三次握手之后,鏈接建立。
為什么一定是三次握手才能建立一個可靠地鏈接?如果不是三次握手,那么在客戶端發送了鏈接請求之后,服務端對這個請求進行確認,就認定這次的鏈接已經成功建立,俗稱的二次握手。這樣的方式的弊端在哪里?
考慮這么一種情況,當客戶端進行第一次握手時,發送了一個報文段,但是這個報文段因為網絡的問題,遲遲沒有到,這時,客戶端又會再一次發送一個連接請求的報文段給服務端,這次成功接收,兩者建立連接,並通信結束,關閉連接。這之后,因為網絡延遲的那個報文段傳到了服務端那里,服務端又以為客戶端要建立新的連接,於是就同意了,向客戶端發送確認。因為是二次握手,所以服務端后續要做的事情,就是等待客戶端發送的消息,但是客戶端是不會理會服務端傳來的確認,所以服務端就會一直在等待客戶端的數據,白白浪費了資源。

抓包分析TCP三次握手的報文段

現在,詳細說一下三次握手具體是做了什么。
第一次握手,客戶端發送一個報文段給服務端,該報文段中標志有SYN標志,該標志表示建立連接,以及一個初始的序列號。
第二次握手時,服務端發送一個報文段給客戶端,該報文段中標志有SYN標志,和ACK標志。ACK標志的值是客戶端發來的初始序號值+ 1,表示對客戶端進行確認,報文段中還有服務端自己的初始序號。
第三次握手時,客戶端發送一個報文段給服務端,該報文段中標志只有ACK標志,該ACK值是服務端的初始序列化的值 + 1,表示對服務端進行確認,以及還有一個序號值,該序號值為客戶端第一次握手時的序號值 + 1。
三次握手建立連接結束。

圖片上共有三行,每一行代表一次握手。我們先看第一行

可以看出,第一次握手時55732端口的程序主動發送一個建立鏈接的報文段給8888端口。這個55732端口是Java程序寫的一個Socket客戶端,8888端口是Socket程序寫的服務端。建立連接的報文段,Flags中,只有SYN是為1的,這表明這是一個建立連接的報文段,該報文段中初始的序列號為0,ACK的number也為0。

第二次握手,是服務端發送給客戶端一個報文段,表示確認收到了客戶端的鏈接請求。該報文段中標志位有兩個一個是ACK,一個SYN。表示收到鏈接請求,端口開放。該報文段中也會發送一個服務端自己的初始序列號。注意,這里ACK的值變成了1,是客戶端初始序列號 + 1才有的。

第三次握手,是客戶端發送給服務端一個報文段,表示確認收到了服務端的確認。因為雙方端口都已經打開,所以客戶端在發,就不會再有SYN標志了,這里只有ACK標志,該標志的值也是1,是因為服務端的初始序列號 + 1造成的。這里的序列號為1,是因為第一次握手,發送了一個SYN標志,該標志會占用1個序號值,但是ACK不會。
對應到上面的狀態圖中,就是客戶端是主動打開,從起始點發送SYN報文段,進入SYN_SENT狀態,然后接受SYN,ACK,走黑粗線的路徑進入到數據傳輸狀態,也就是ESTABLISHED,對於服務端而言,就是從起始點走虛線的部分,被動打開后,接受客戶端的SYN,進入SYN_RCVD,最后,接受客戶端第三次握手的ACK,進入數據傳輸狀態,也就是ESTABLISHED。

TCP協議之四次揮手

TCP協議是一種全雙工協議,擁有半關閉的特性。

全雙工的意思是A可以往B發送數據,B同時也可以給A發送數據。
半雙工的意思是A可以往B發送數據,B也可以給A發送數據,但是兩者不能同時。
單工的意思是只能A給B發送數據,或者B給A發送數據。
半關閉的意思是將全雙工,變成單工,也就是如果B關閉,是指B不能給A發數據了,但是A可以給B發

所以TCP協議如果要正常的關閉客戶端與服務端的鏈接,需要四次報文段,也就是4次揮手。
首先,客戶端因為應用程序的執行完畢,會主動開始斷開鏈接,這時會發送一個含有FIN標志位的報文段。這表明客戶端不會再發送數據給服務端。這時第一次揮手。
然后,服務端接收到這個報文段,就會發送一個含有ACK標志的報文段給客戶端,表示確認收到了關閉的報文段。這是第二次揮手。
然后,服務端在處理完服務端的事情后,也會發送一個含有FIN的報文段給客戶端,表示服務端不會再發送數據給客戶端。這是第三次揮手。
最后,客戶端收到這個報文段后,就會發送一個含有ACK的報文段給服務端,表示確認收到了關閉的報文段。這是第四次揮手。至此,鏈接全部關閉。

抓包分析TCP四次揮手的報文段


不用看黑色報文,4行代表關閉的4次揮手的過程,每一行是一次揮手。
第一行,是客戶端主動關閉鏈接,發送一個含有FIN的報文段,這是第一次揮手
第二行,是服務端確認客戶端的FIN報文,發送一個ACK的確認報文,該ACK的值是9,而第一行的序列號的8,因為與SYN一樣,FIN也占一個序列號。
忽略黑的后第三行,服務端發送一個含有FIN的報文段,這是第三次揮手。
第四行,客戶端會這個FIN報文段進行確認,發送了一個ACK報文段。該ACK的值是第三行的序列號 + 1。

對應到上面的狀態圖中,先說服務端的狀態轉移,因為收到了客戶端的FIN,所以發送一個ACK給客戶端,同時自己進入到CLOSE_WAIT狀態,等待服務端應用程序結束,發送FIN給客戶端,自己進入LAST_ACK狀態,等待最后的ACK到來,接收到ACK,結束狀態。

客戶端因為先發起關閉,狀態比較復雜,他先發送一個FIN給服務端,自己進入了FIN_WAIT_1狀態,這時他等待接收服務端的報文,該報文會有三種可能:

  1. 只有服務端的ACK
  2. 只有服務端的FIN
  3. 基於服務端的ACK,又有FIN

對於第一種,該ACK是服務端確認了客戶端的FIN而發的,這時客戶端會進入FIN_WAIT_2狀態,這是當他收到服務端的FIN來時,發送了一個ACK,會進入到TIME_WAIT狀態,他要在這個狀態等待2MSL的時間,1個MSL是報文段在網絡的最長時間,客戶端等待2MSL,是為了當最后一個ACK丟失時,可以在發送一次,因為這時,服務端在等待超時后在發送一個FIN給客戶端,所以客戶端也知道了ACK丟失了。

對於第二種,只有服務端的FIN的時,會發送一個ACK給服務端,客戶端進入CLOSING狀態,然后接收到服務端的ACK時,也會進入TIME_WAIT狀態。

對於第三種,同時都收到了,就省略了進入CLOSING狀態,直接進入TIME_WAIT狀態。抓包分析的截圖,就是這種情況。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM