(轉載) 詳解 TCP 連線的“ 三次握手 ”與“ 四次揮手 ”
https://baijiahao.baidu.com/s?id=1654225744653405133&wfr=spider&for=pc
TCP connection
客戶端與伺服器之間資料的傳送和返回的過程當中需要建立一個叫TCP connection的東西;
由於TCP不存在連線的概念,只存在請求和響應,請求和響應都是資料包,它們之間都是經過由TCP建立的一個從客戶端發起,伺服器接收的類似連線的通道,這個連線可以一直保持,http請求是在這個連線的基礎上傳送的;
在一個TCP連線上是可以傳送多個http請求的,不同的版本這個模式不一樣。
在HTTP/1.0中這個TCP連線是在http請求建立的時候同步建立的,http請求傳送到伺服器端,伺服器端響應了之後,這個TCP連線就關閉了;
HTTP/1.1中可以以某種方式宣告這個連線一直保持,一個請求傳輸完之後,另一個請求可以接著傳輸。這樣的好處是:在建立一個TCP連線的過程中需要“三次握手”的消耗,“三次握手”代表有三次網路傳輸。
如果TCP連線保持,第二個請求傳送就沒有這“三次握手”的消耗。HTTP/2中同一個TCP連線裡還可以併發地傳輸http請求。
TCP報文格式簡介
其中比較重要的欄位有:
(1)序號(sequence number):Seq序號,佔32位,用來標識從TCP源端向目的端傳送的位元組流,發起方傳送資料時對此進行標記。
(2)確認號(acknowledgement number):Ack序號,佔32位,只有ACK標誌位為1時,確認序號欄位才有效,Ack=Seq+1。
(3)標誌位(Flags):共6個,即URG、ACK、PSH、RST、SYN、FIN等。具體含義如下:
URG:緊急指標(urgent pointer)有效。ACK:確認序號有效。PSH:接收方應該儘快將這個報文交給應用層。RST:重置連線。SYN:發起一個新連線。FIN:釋放一個連線。
需要注意的是:
不要將確認序號Ack與標誌位中的ACK搞混了。確認方Ack=發起方Seq+1,兩端配對。
TCP的三次握手(Three-Way Handshake)
1.”三次握手”的詳解
所謂的三次握手即TCP連線的建立。這個連線必須是一方主動開啟,另一方被動開啟的。以下為客戶端主動發起連線的圖解:
握手之前主動開啟連線的客戶端結束CLOSED階段,被動開啟的伺服器端也結束CLOSED階段,並進入LISTEN階段。隨後開始“三次握手”:
(1)首先客戶端向伺服器端傳送一段TCP報文,其中:
標記位為SYN,表示“請求建立新連線”;序號為Seq=X(X一般為1);隨後客戶端進入SYN-SENT階段。(2)伺服器端接收到來自客戶端的TCP報文之後,結束LISTEN階段。並返回一段TCP報文,其中:
標誌位為SYN和ACK,表示“確認客戶端的報文Seq序號有效,伺服器能正常接收客戶端傳送的資料,並同意建立新連線”(即告訴客戶端,伺服器收到了你的資料);序號為Seq=y;確認號為Ack=x+1,表示收到客戶端的序號Seq並將其值加1作為自己確認號Ack的值;隨後伺服器端進入SYN-RCVD階段。(3)客戶端接收到來自伺服器端的確認收到資料的TCP報文之後,明確了從客戶端到伺服器的資料傳輸是正常的,結束SYN-SENT階段。並返回最後一段TCP報文。其中:
標誌位為ACK,表示“確認收到伺服器端同意連線的訊號”(即告訴伺服器,我知道你收到我發的資料了);序號為Seq=x+1,表示收到伺服器端的確認號Ack,並將其值作為自己的序號值;確認號為Ack=y+1,表示收到伺服器端序號Seq,並將其值加1作為自己的確認號Ack的值;隨後客戶端進入ESTABLISHED階段。伺服器收到來自客戶端的“確認收到伺服器資料”的TCP報文之後,明確了從伺服器到客戶端的資料傳輸是正常的。結束SYN-SENT階段,進入ESTABLISHED階段。
在客戶端與伺服器端傳輸的TCP報文中,雙方的確認號Ack和序號Seq的值,都是在彼此Ack和Seq值的基礎上進行計算的,這樣做保證了TCP報文傳輸的連貫性。一旦出現某一方發出的TCP報文丟失,便無法繼續"握手",以此確保了"三次握手"的順利完成。
此後客戶端和伺服器端進行正常的資料傳輸。這就是“三次握手”的過程。
2.“三次握手”的動態過程
3.“三次握手”的通俗理解
舉個栗子:把客戶端比作男孩,伺服器比作女孩。用他們的交往來說明“三次握手”過程:
(1)男孩喜歡女孩,於是寫了一封信告訴女孩:我愛你,請和我交往吧!;寫完信之後,男孩焦急地等待,因為不知道信能否順利傳達給女孩。
(2)女孩收到男孩的情書後,心花怒放,原來我們是兩情相悅呀!於是給男孩寫了一封回信:我收到你的情書了,也明白了你的心意,其實,我也喜歡你!我願意和你交往!;
寫完信之後,女孩也焦急地等待,因為不知道回信能否能順利傳達給男孩。
(3)男孩收到回信之後很開心,因為發出的情書女孩收到了,並且從回信中知道了女孩喜歡自己,並且願意和自己交往。然後男孩又寫了一封信告訴女孩:你的心意和信我都收到了,謝謝你,還有我愛你!
女孩收到男孩的回信之後,也很開心,因為發出的情書男孩收到了。由此男孩女孩雙方都知道了彼此的心意,之後就快樂地交流起來了~~
這就是通俗版的“三次握手”,期間一共往來了三封信也就是“三次握手”,以此確認兩個方向上的資料傳輸通道是否正常。
4.為什麼要進行第三次握手?
為了防止伺服器端開啟一些無用的連線增加伺服器開銷以及防止已失效的連線請求報文段突然又傳送到了服務端,因而產生錯誤。
由於網路傳輸是有延時的(要通過網路光纖和各種中間代理伺服器),在傳輸的過程中,比如客戶端發起了SYN=1建立連線的請求(第一次握手)。
如果伺服器端就直接建立了這個連線並返回包含SYN、ACK和Seq等內容的資料包給客戶端,這個資料包因為網路傳輸的原因丟失了,丟失之後客戶端就一直沒有接收到伺服器返回的資料包。
客戶端可能設定了一個超時時間,時間到了就關閉了連線建立的請求。再重新發出建立連線的請求,而伺服器端是不知道的,如果沒有第三次握手告訴伺服器端客戶端收的到伺服器端傳輸的資料的話,
伺服器端是不知道客戶端有沒有接收到伺服器端返回的資訊的。
這個過程可理解為:
這樣沒有給伺服器端一個建立還是關閉連線埠的請求,伺服器端的埠就一直開著,等到客戶端因超時重新發出請求時,伺服器就會重新開啟一個埠連線。那麼伺服器端上沒有接收到請求資料的上一個埠就一直開著,長此以往,這樣的埠多了,就會造成伺服器端開銷的嚴重浪費。
還有一種情況是已經失效的客戶端發出的請求資訊,由於某種原因傳輸到了伺服器端,伺服器端以為是客戶端發出的有效請求,接收後產生錯誤。
所以我們需要“第三次握手”來確認這個過程,讓客戶端和伺服器端能夠及時地察覺到因為網路等一些問題導致的連線建立失敗,這樣伺服器端的埠就可以關閉了不用一直等待。
也可以這樣理解:“第三次握手”是客戶端向伺服器端傳送資料,這個資料就是要告訴伺服器,客戶端有沒有收到伺服器“第二次握手”時傳過去的資料。若傳送的這個資料是“收到了”的資訊,接收後伺服器就正常建立TCP連線,否則建立TCP連線失敗,伺服器關閉連線埠。由此減少伺服器開銷和接收到失效請求發生的錯誤。
5.抓包驗證
下面是用抓包工具抓到的一些資料包,可用來分析TCP的三次握手:
圖中顯示的就是完整的TCP連線的”三次握手”過程。在52528 -> 80中,52528是本地(客戶端)埠,80是伺服器的埠。80埠和52528埠之間的三次來回就是"三次握手"過程。
注意到”第一次握手”客戶端傳送的TCP報文中以[SYN]作為標誌位,並且客戶端序號Seq=0;
接下來”第二次握手”伺服器返回的TCP報文中以[SYN,ACK]作為標誌位;並且伺服器端序號Seq=0;確認號Ack=1(“第一次握手”中客戶端序號Seq的值+1);
最後”第三次握手”客戶端再向伺服器端傳送的TCP報文中以[ACK]作為標誌位;
其中客戶端序號Seq=1(“第二次握手”中伺服器端確認號Ack的值);確認號Ack=1(“第二次握手”中伺服器端序號Seq的值+1)。
這就完成了”三次握手”的過程,符合前面分析的結果。
TCP的四次揮手(Four-Way Wavehand)
1、前言
對於"三次握手"我們耳熟能詳,因為其相對的簡單。但是,我們卻不常聽見“四次揮手”,就算聽過也未必能詳細地說明白它的具體過程。下面就為大家詳盡,直觀,完整地介紹“四次揮手”的過程。
2、“四次揮手”的詳解
所謂的四次揮手即TCP連線的釋放(解除)。連線的釋放必須是一方主動釋放,另一方被動釋放。以下為客戶端主動發起釋放連線的圖解:
揮手之前主動釋放連線的客戶端結束ESTABLISHED階段。隨後開始“四次揮手”:
(1)首先客戶端想要釋放連線,向伺服器端傳送一段TCP報文,其中:
標記位為FIN,表示“請求釋放連線“;序號為Seq=U;隨後客戶端進入FIN-WAIT-1階段,即半關閉階段。並且停止在客戶端到伺服器端方向上傳送資料,但是客戶端仍然能接收從伺服器端傳輸過來的資料。注意:這裡不傳送的是正常連線時傳輸的資料(非確認報文),而不是一切資料,所以客戶端仍然能傳送ACK確認報文。
(2)伺服器端接收到從客戶端發出的TCP報文之後,確認了客戶端想要釋放連線,隨後伺服器端結束ESTABLISHED階段,進入CLOSE-WAIT階段(半關閉狀態)並返回一段TCP報文,其中:
標記位為ACK,表示“接收到客戶端傳送的釋放連線的請求”;序號為Seq=V;確認號為Ack=U+1,表示是在收到客戶端報文的基礎上,將其序號Seq值加1作為本段報文確認號Ack的值;隨後伺服器端開始準備釋放伺服器端到客戶端方向上的連線。客戶端收到從伺服器端發出的TCP報文之後,確認了伺服器收到了客戶端發出的釋放連線請求,隨後客戶端結束FIN-WAIT-1階段,進入FIN-WAIT-2階段
前"兩次揮手"既讓伺服器端知道了客戶端想要釋放連線,也讓客戶端知道了伺服器端了解了自己想要釋放連線的請求。於是,可以確認關閉客戶端到伺服器端方向上的連線了
(3)伺服器端自從發出ACK確認報文之後,經過CLOSED-WAIT階段,做好了釋放伺服器端到客戶端方向上的連線準備,再次向客戶端發出一段TCP報文,其中:
標記位為FIN,ACK,表示“已經準備好釋放連線了”。注意:這裡的ACK並不是確認收到伺服器端報文的確認報文。序號為Seq=W;確認號為Ack=U+1;表示是在收到客戶端報文的基礎上,將其序號Seq值加1作為本段報文確認號Ack的值。隨後伺服器端結束CLOSE-WAIT階段,進入LAST-ACK階段。並且停止在伺服器端到客戶端的方向上傳送資料,但是伺服器端仍然能夠接收從客戶端傳輸過來的資料。
(4)客戶端收到從伺服器端發出的TCP報文,確認了伺服器端已做好釋放連線的準備,結束FIN-WAIT-2階段,進入TIME-WAIT階段,並向伺服器端傳送一段報文,其中:
標記位為ACK,表示“接收到伺服器準備好釋放連線的訊號”。序號為Seq=U+1;表示是在收到了伺服器端報文的基礎上,將其確認號Ack值作為本段報文序號的值。確認號為Ack=W+1;表示是在收到了伺服器端報文的基礎上,將其序號Seq值作為本段報文確認號的值。隨後客戶端開始在TIME-WAIT階段等待2MSL
為什麼要客戶端要等待2MSL呢?見後文。
伺服器端收到從客戶端發出的TCP報文之後結束LAST-ACK階段,進入CLOSED階段。由此正式確認關閉伺服器端到客戶端方向上的連線。
客戶端等待完2MSL之後,結束TIME-WAIT階段,進入CLOSED階段,由此完成“四次揮手”。
後“兩次揮手”既讓客戶端知道了伺服器端準備好釋放連線了,也讓伺服器端知道了客戶端了解了自己準備好釋放連線了。於是,可以確認關閉伺服器端到客戶端方向上的連線了,由此完成“四次揮手”。
與“三次揮手”一樣,在客戶端與伺服器端傳輸的TCP報文中,雙方的確認號Ack和序號Seq的值,都是在彼此Ack和Seq值的基礎上進行計算的,這樣做保證了TCP報文傳輸的連貫性,一旦出現某一方發出的TCP報文丟失,便無法繼續"揮手",以此確保了"四次揮手"的順利完成。
3、“四次揮手”的通俗理解
舉個栗子:把客戶端比作男孩,伺服器比作女孩。通過他們的分手來說明“四次揮手”過程。
"第一次揮手":日久見人心,男孩發現女孩變成了自己討厭的樣子,忍無可忍,於是決定分手,隨即寫了一封信告訴女孩。“第二次揮手”:女孩收到信之後,知道了男孩要和自己分手,怒火中燒,心中暗罵:你算什麼東西,當初你可不是這個樣子的!於是立馬給男孩寫了一封回信:分手就分手,給我點時間,我要把你的東西整理好,全部還給你!男孩收到女孩的第一封信之後,明白了女孩知道自己要和她分手。隨後等待女孩把自己的東西收拾好。“第三次揮手”:過了幾天,女孩把男孩送的東西都整理好了,於是再次寫信給男孩:你的東西我整理好了,快把它們拿走,從此你我恩斷義絕!“第四次揮手”:男孩收到女孩第二封信之後,知道了女孩收拾好東西了,可以正式分手了,於是再次寫信告訴女孩:我知道了,這就去拿回來!這裡雙方都有各自的堅持。女孩自發出第二封信開始,限定一天內收不到男孩回信,就會再發一封信催促男孩來取東西!男孩自發出第二封信開始,限定兩天內沒有再次收到女孩的信就認為,女孩收到了自己的第二封信;若兩天內再次收到女孩的來信,就認為自己的第二封信女孩沒收到,需要再寫一封信,再等兩天…..
倘若雙方信都能正常收到,最少只用四封信就能徹底分手!這就是“四次揮手”。
4.為什麼“握手”是三次,“揮手”卻要四次?
TCP建立連線時之所以只需要"三次握手",是因為在第二次"握手"過程中,伺服器端傳送給客戶端的TCP報文是以SYN與ACK作為標誌位的。SYN是請求連線標誌,表示伺服器端同意建立連線;ACK是確認報文,表示告訴客戶端,伺服器端收到了它的請求報文。
即SYN建立連線報文與ACK確認接收報文是在同一次"握手"當中傳輸的,所以"三次握手"不多也不少,正好讓雙方明確彼此資訊互通。
TCP釋放連線時之所以需要“四次揮手”,是因為FIN釋放連線報文與ACK確認接收報文是分別由第二次和第三次"握手"傳輸的。為何建立連線時一起傳輸,釋放連線時卻要分開傳輸?
建立連線時,被動方伺服器端結束CLOSED階段進入“握手”階段並不需要任何準備,可以直接返回SYN和ACK報文,開始建立連線。釋放連線時,被動方伺服器,突然收到主動方客戶端釋放連線的請求時並不能立即釋放連線,因為還有必要的資料需要處理,所以伺服器先返回ACK確認收到報文,經過CLOSE-WAIT階段準備好釋放連線之後,才能返回FIN釋放連線報文。
所以是“三次握手”,“四次揮手”。
5.為什麼客戶端在TIME-WAIT階段要等2MSL?
為的是確認伺服器端是否收到客戶端發出的ACK確認報文
當客戶端發出最後的ACK確認報文時,並不能確定伺服器端能夠收到該段報文。所以客戶端在傳送完ACK確認報文之後,會設定一個時長為2MSL的計時器。MSL指的是Maximum Segment Lifetime:一段TCP報文在傳輸過程中的最大生命週期。2MSL即是伺服器端發出為FIN報文和客戶端發出的ACK確認報文所能保持有效的最大時長。
伺服器端在1MSL內沒有收到客戶端發出的ACK確認報文,就會再次向客戶端發出FIN報文;
如果客戶端在2MSL內,再次收到了來自伺服器端的FIN報文,說明伺服器端由於各種原因沒有接收到客戶端發出的ACK確認報文。客戶端再次向伺服器端發出ACK確認報文,計時器重置,重新開始2MSL的計時;否則客戶端在2MSL內沒有再次收到來自伺服器端的FIN報文,說明伺服器端正常接收了ACK確認報文,客戶端可以進入CLOSED階段,完成“四次揮手”。
所以,客戶端要經歷時長為2SML的TIME-WAIT階段;這也是為什麼客戶端比伺服器端晚進入CLOSED階段的原因
6.抓包驗證
圖中顯示的就是完整的TCP連線釋放的”四次揮手”過程。在 80 -> 55389 中,假設80是本地(客戶端)埠,55389是伺服器埠。80埠與55389之間的四次來回就是"四次揮手"過程。
”第一次揮手”客戶端傳送的FIN請求釋放連線報文以[FIN,ACK]作為標誌位,其中報文序號Seq=2445;確認號Ack=558;注意:這裡與“第三次握手”的ACK並不是表示確認的ACK報文。”第二次揮手”伺服器端返回的ACK確認報文以[ACK]作為標誌位;其中報文序號Seq=558;確認號Ack=2246;”第三次揮手”伺服器端繼續返回的FIN同意釋放連線報文以[FIN,ACK]作為標誌位;其中報文序號Seq=558;確認號Ack=2246;”第四次揮手”客戶端發出的ACK確認接收報文以[ACK]作為標誌位;其中報文序號Seq=2446;確認號Ack=559。後一次“揮手”傳輸報文中的序號Seq值等於前一次"握手"傳輸報文中的確認號Ack值;後一次“揮手”傳輸報文中的確認號Ack值等於前一次"握手"傳輸報文中的序號Seq值;
故這是連續的“四次揮手”過程,與前面的分析相符。