客戶端與服務器之間數據的發送和返回的過程當中需要創建一個叫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)。
這就完成了”三次握手”的過程,符合前面分析的結果。
總結
1.客戶端發送請求到服務端,服務端知道客戶端發送正常,自己接受正常
ACK=1 seq=x
2.服務器發給客戶端,客戶端知道自己發送接受正常,服務端發送接受正常。
Ack=1 ack=X+1 SYN=1 seq=y
3.客戶端發給服務端,服務端知道客戶端發型接受正常,自己發送接受正常
seq=x+1 ACK=1 ack=y+1