天天看點

詳解 TCP 連接配接的“ 三次握手 ”與“ 四次揮手 ”

TCP connection

詳解 TCP 連接配接的“ 三次握手 ”與“ 四次揮手 ”
詳解 TCP 連接配接的“ 三次握手 ”與“ 四次揮手 ”

用戶端與伺服器之間資料的發送和傳回的過程當中需要建立一個叫TCP connection的東西;

由于TCP不存在連接配接的概念,隻存在請求和響應,請求和響應都是資料包,它們之間都是經過由TCP建立的一個從用戶端發起,伺服器接收的類似連接配接的通道,這個連接配接可以一直保持,http請求是在這個連接配接的基礎上發送的;

在一個TCP連接配接上是可以發送多個http請求的,不同的版本這個模式不一樣。

在HTTP/1.0中這個TCP連接配接是在http請求建立的時候同步建立的,http請求發送到伺服器端,伺服器端響應了之後,這個TCP連接配接就關閉了;

HTTP/1.1中可以以某種方式聲明這個連接配接一直保持,一個請求傳輸完之後,另一個請求可以接着傳輸。這樣的好處是:在建立一個TCP連接配接的過程中需要“三次握手”的消耗,“三次握手”代表有三次網絡傳輸。

如果TCP連接配接保持,第二個請求發送就沒有這“三次握手”的消耗。HTTP/2中同一個TCP連接配接裡還可以并發地傳輸http請求。

TCP封包格式簡介

詳解 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連接配接的建立。這個連接配接必須是一方主動打開,另一方被動打開的。以下為用戶端主動發起連接配接的圖解:

詳解 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.“三次握手”的通俗了解

詳解 TCP 連接配接的“ 三次握手 ”與“ 四次揮手 ”

舉個栗子:把用戶端比作男孩,伺服器比作女孩。用他們的交往來說明“三次握手”過程:

(1)男孩喜歡女孩,于是寫了一封信告訴女孩:我愛你,請和我交往吧!;寫完信之後,男孩焦急地等待,因為不知道信能否順利傳達給女孩。

(2)女孩收到男孩的情書後,心花怒放,原來我們是兩情相悅呀!于是給男孩寫了一封回信:我收到你的情書了,也明白了你的心意,其實,我也喜歡你!我願意和你交往!;

寫完信之後,女孩也焦急地等待,因為不知道回信能否能順利傳達給男孩。

(3)男孩收到回信之後很開心,因為發出的情書女孩收到了,并且從回信中知道了女孩喜歡自己,并且願意和自己交往。然後男孩又寫了一封信告訴女孩:你的心意和信我都收到了,謝謝你,還有我愛你!

女孩收到男孩的回信之後,也很開心,因為發出的情書男孩收到了。由此男孩女孩雙方都知道了彼此的心意,之後就快樂地交流起來了~~

這就是通俗版的“三次握手”,期間一共往來了三封信也就是“三次握手”,以此确認兩個方向上的資料傳輸通道是否正常。

4.為什麼要進行第三次握手?

為了防止伺服器端開啟一些無用的連接配接增加伺服器開銷以及防止已失效的連接配接請求封包段突然又傳送到了服務端,因而産生錯誤。

由于網絡傳輸是有延時的(要通過網絡光纖和各種中間代理伺服器),在傳輸的過程中,比如用戶端發起了SYN=1建立連接配接的請求(第一次握手)。

如果伺服器端就直接建立了這個連接配接并傳回包含SYN、ACK和Seq等内容的資料包給用戶端,這個資料包因為網絡傳輸的原因丢失了,丢失之後用戶端就一直沒有接收到伺服器傳回的資料包。

用戶端可能設定了一個逾時時間,時間到了就關閉了連接配接建立的請求。再重新發出建立連接配接的請求,而伺服器端是不知道的,如果沒有第三次握手告訴伺服器端用戶端收的到伺服器端傳輸的資料的話,

伺服器端是不知道用戶端有沒有接收到伺服器端傳回的資訊的。

這個過程可了解為:

詳解 TCP 連接配接的“ 三次握手 ”與“ 四次揮手 ”

這樣沒有給伺服器端一個建立還是關閉連接配接端口的請求,伺服器端的端口就一直開着,等到用戶端因逾時重新送出請求時,伺服器就會重新開啟一個端口連接配接。那麼伺服器端上沒有接收到請求資料的上一個端口就一直開着,長此以往,這樣的端口多了,就會造成伺服器端開銷的嚴重浪費。

還有一種情況是已經失效的用戶端發出的請求資訊,由于某種原因傳輸到了伺服器端,伺服器端以為是用戶端發出的有效請求,接收後産生錯誤。

是以我們需要“第三次握手”來确認這個過程,讓用戶端和伺服器端能夠及時地察覺到因為網絡等一些問題導緻的連接配接建立失敗,這樣伺服器端的端口就可以關閉了不用一直等待。

也可以這樣了解:“第三次握手”是用戶端向伺服器端發送資料,這個資料就是要告訴伺服器,用戶端有沒有收到伺服器“第二次握手”時傳過去的資料。若發送的這個資料是“收到了”的資訊,接收後伺服器就正常建立TCP連接配接,否則建立TCP連接配接失敗,伺服器關閉連接配接端口。由此減少伺服器開銷和接收到失效請求發生的錯誤。

5.抓包驗證

下面是用抓包工具抓到的一些資料包,可用來分析TCP的三次握手:

詳解 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連接配接的釋放(解除)。連接配接的釋放必須是一方主動釋放,另一方被動釋放。以下為用戶端主動發起釋放連接配接的圖解:

詳解 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、“四次揮手”的通俗了解

詳解 TCP 連接配接的“ 三次握手 ”與“ 四次揮手 ”

舉個栗子:把用戶端比作男孩,伺服器比作女孩。通過他們的分手來說明“四次揮手”過程。

"第一次揮手":日久見人心,男孩發現女孩變成了自己讨厭的樣子,忍無可忍,于是決定分手,随即寫了一封信告訴女孩。

“第二次揮手”:女孩收到信之後,知道了男孩要和自己分手,怒火中燒,心中暗罵:你算什麼東西,當初你可不是這個樣子的!于是立馬給男孩寫了一封回信:分手就分手,給我點時間,我要把你的東西整理好,全部還給你!男孩收到女孩的第一封信之後,明白了女孩知道自己要和她分手。随後等待女孩把自己的東西收拾好。

“第三次揮手”:過了幾天,女孩把男孩送的東西都整理好了,于是再次寫信給男孩:你的東西我整理好了,快把它們拿走,從此你我恩斷義絕!

“第四次揮手”:男孩收到女孩第二封信之後,知道了女孩收拾好東西了,可以正式分手了,于是再次寫信告訴女孩:我知道了,這就去拿回來!

這裡雙方都有各自的堅持。

女孩自發出第二封信開始,限定一天内收不到男孩回信,就會再發一封信催促男孩來取東西!

男孩自發出第二封信開始,限定兩天内沒有再次收到女孩的信就認為,女孩收到了自己的第二封信;若兩天内再次收到女孩的來信,就認為自己的第二封信女孩沒收到,需要再寫一封信,再等兩天…..

倘若雙方信都能正常收到,最少隻用四封信就能徹底分手!這就是“四次揮手”。

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.抓包驗證