客戶端與服務器之間數據的發送和返回的過程中須要建立一個叫TCP connection的東西;
因爲TCP不存在鏈接的概念,只存在請求和響應,請求和響應都是數據包,它們之間都是通過由TCP建立的一個從客戶端發起,服務器接收的相似鏈接的通道,這個鏈接能夠一直保持,http請求是在這個鏈接的基礎上發送的;html
在一個TCP鏈接上是能夠發送多個http請求的,不一樣的版本這個模式不同。服務器
在HTTP/1.0中這個TCP鏈接是在http請求建立的時候同步建立的,http請求發送到服務器端,服務器端響應了以後,這個TCP鏈接就關閉了;
HTTP/1.1中能夠以某種方式聲明這個鏈接一直保持,一個請求傳輸完以後,另外一個請求能夠接着傳輸。這樣的好處是:在建立一個TCP鏈接的過程當中須要「三次握手」的消耗,「三次握手」表明有三次網絡傳輸。
若是TCP鏈接保持,第二個請求發送就沒有這「三次握手」的消耗。HTTP/2中同一個TCP鏈接裏還能夠併發地傳輸http請求。網絡
其中比較重要的字段有:併發
(1)序號(sequence number):Seq序號,佔32位,用來標識從TCP源端向目的端發送的字節流,發起方發送數據時對此進行標記。tcp
(2)確認號(acknowledgement number):Ack序號,佔32位,只有ACK標誌位爲1時,確認序號字段纔有效,Ack=Seq+1。工具
(3)標誌位(Flags):共6個,即URG、ACK、PSH、RST、SYN、FIN等,具體含義以下:計算機網絡
須要注意的是:3d
所謂的三次握手即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報文丟失,便沒法繼續"握手",以此確保了"三次握手"的順利完成。
舉個栗子:把客戶端比做男孩,服務器比做女孩。用他們的交往來講明「三次握手」過程:
(1)男孩喜歡女孩,因而寫了一封信告訴女孩:我愛你,請和我交往吧!;寫完信以後,男孩焦急地等待,由於不知道信可否順利傳達給女孩。
(2)女孩收到男孩的情書後,心花盛開,原來咱們是兩情相悅呀!因而給男孩寫了一封回信:我收到你的情書了,也明白了你的心意,其實,我也喜歡你!我願意和你交往!;
寫完信以後,女孩也焦急地等待,由於不知道回信可否能順利傳達給男孩。
(3)男孩收到回信以後很開心,由於發出的情書女孩收到了,而且從回信中知道了女孩喜歡本身,而且願意和本身交往。而後男孩又寫了一封信告訴女孩:你的心意和信我都收到了,謝謝你,還有我愛你!
女孩收到男孩的回信以後,也很開心,由於發出的情書男孩收到了。由此男孩女孩雙方都知道了彼此的心意,以後就快樂地交流起來了~~
因爲網絡傳輸是有延時的(要經過網絡光纖和各類中間代理服務器),在傳輸的過程當中,好比客戶端發起了SYN=1建立鏈接的請求(第一次握手)。
若是服務器端就直接建立了這個鏈接並返回包含SYN、ACK和Seq等內容的數據包給客戶端,這個數據包由於網絡傳輸的緣由丟失了,丟失以後客戶端就一直沒有接收到服務器返回的數據包。
客戶端可能設置了一個超時時間,時間到了就關閉了鏈接建立的請求。再從新發出建立鏈接的請求,而服務器端是不知道的,若是沒有第三次握手告訴服務器端客戶端收的到服務器端傳輸的數據的話,
服務器端是不知道客戶端有沒有接收到服務器端返回的信息的。
這個過程可理解爲:
這樣沒有給服務器端一個建立仍是關閉鏈接端口的請求,服務器端的端口就一直開着,等到客戶端因超時從新發出請求時,服務器就會從新開啓一個端口鏈接。那麼服務器端上沒有接收到請求數據的上一個端口就一直開着,久而久之,這樣的端口多了,就會形成服務器端開銷的嚴重浪費。
還有一種狀況是已經失效的客戶端發出的請求信息,因爲某種緣由傳輸到了服務器端,服務器端覺得是客戶端發出的有效請求,接收後產生錯誤。
因此咱們須要「第三次握手」來確認這個過程,讓客戶端和服務器端可以及時地察覺到由於網絡等一些問題致使的鏈接建立失敗,這樣服務器端的端口就能夠關閉了不用一直等待。
也能夠這樣理解:「第三次握手」是客戶端向服務器端發送數據,這個數據就是要告訴服務器,客戶端有沒有收到服務器「第二次握手」時傳過去的數據。若發送的這個數據是「收到了」的信息,接收後服務器就正常創建TCP鏈接,不然創建TCP鏈接失敗,服務器關閉鏈接端口。由此減小服務器開銷和接收到失效請求發生的錯誤。
下面是用抓包工具抓到的一些數據包,可用來分析TCP的三次握手:
圖中顯示的就是完整的TCP鏈接的」三次握手」過程。在52528 -> 80中,52528是本地(客戶端)端口,80是服務器的端口。80端口和52528端口之間的三次來回就是"三次握手"過程。
參考資料:
深刻淺出圖解【計算機網絡】 之 【TCP可靠傳輸的實現: 三次握手+滑動窗口】
使用 WireShark 分析 TCP/IP 三次握手 和 四次揮手