您現在的位置是:首頁 > 手機遊戲首頁手機遊戲

HTTP 三次握手 四次揮手

簡介過程描述先上一張TCP報文結構圖,待會我們會回來看這張圖:TCP報文結構先上三次握手的流程圖:三次握手接下來我們來詳細講解下上圖的過程:客戶主機發起連線請求,設定SYN標誌位為1,同時客戶端隨機選擇了一個初始序號client_isn,並且存

初始編號是什麼

前言

結束後花了一段時間整理了下思路,參考和查閱了一下資料,整理如下:來源:程式設計充電寶

作者:在所不辭

問題描述

你能否講解一下TCP的三次握手與四次揮手呢?

面試官如果從整體到區域性入手,那我們就先講講

整個三次握手和四次揮手的過程

,但不要忘記,講的同時應該適當

體現你對該知識點掌握的深度和廣度

,具體怎麼說,我們後面慢慢道來。

三次握手

所謂的握手即一次發包到接收的過程,可能從客戶端傳送到服務端,也可能從服務端傳送到客戶端。

過程描述

先上一張TCP報文結構圖,待會我們會回來看這張圖:

HTTP 三次握手 四次揮手

TCP報文結構

先上三次握手的流程圖:

HTTP 三次握手 四次揮手

三次握手

接下來我們來詳細講解下上圖的過程:

客戶主機發起連線請求,設定SYN標誌位為1,同時客戶端隨機選擇了一個初始序號client_isn,並且存放在TCP報文欄位的序號中,如下圖:

HTTP 三次握手 四次揮手

第一次握手:SYN報文

接下來,當服務端接收到該報文後,會為其分配TCP 快取和變數(這使得TCP容易受到被稱為SYN 洪泛攻擊的拒絕服務攻擊)緊接著,服務端會返回一個SYNACK 報文到客戶端,其中SYN標誌位為1,確認號設定為client_isn + 1,並且選一個自己的初始序號server_isn,並放置在序號欄位中,如下圖:

HTTP 三次握手 四次揮手

第二次握手:SYNACK報文

當收到伺服器發來的SYNACK報文段後,客戶端也需要給該連線分配快取和變數,然後再次傳送一個確認報文給服務端,其中,SYN標誌位設定為0,將確認號設定為server_isn + 1,另外,此次報文可以攜帶負載資料:

HTTP 三次握手 四次揮手

第三次握手:ACK報文

細節拓展

三次握手的狀態轉換圖(建議達到能默寫下來的熟練程度)

HTTP 三次握手 四次揮手

三次握手狀態圖

伺服器為什麼要使用特殊的初始序號server_isn?這為什麼是必要的呢?

這個細節和問題深究第3題是一致的,伺服器使用特定的初始序列號 server_isn(從源和目的地IP和埠的雜湊中獲取)可以用來抵禦SYN洪水攻擊。具體為什麼,以及什麼是SYN 洪泛攻擊,問題深究部分我們會再詳談。

為了下文描述方便,我們將三次握手分別稱為:SYN 報文、SYNACK 報文、ACK 報文

問題深究

1。為什麼要三次握手而不是兩次?

簡單來說,三次握手的目的是為了讓雙方

驗證各自的接收能力和傳送能力

第一次握手,A 傳送SYN到B,B接收到了後,能確認什麼呢? 顯然,B能確認A的傳送能力和B的接收能力;

第二次握手,B傳送SYNACK到A,A接收到後,能確認什麼呢? A能確認B的傳送能力和A自己的接收能力,此外,A收到了SYNACK,那麼說明前面A發的SYN成功到達B的手中,所以也能確認A自己的傳送能力和B的接收能力;至此,A已經確認了雙方各自的傳送能力和接收能力都是OK的,因此轉為ESTABLISHED狀態;

第三次握手,A傳送ACK到B,B接收後,能確認什麼呢?

直接的,B能確認A的傳送能力和B的接收能力,另外由於B能收到ACK說明前面傳送的SYNACK已經成功被接受了,說明能確認A的接收能力和B的傳送能力。

如果使用兩次握手,就不能確認上述所說的四種能力,那麼就會導致問題。

假定不採用第三次報文握手,那麼只要B發出確認,新的連線就建立了。

現假定一種異常情況,即A發出的SYN報文段並沒有丟失,而是在某些網路節點長時間滯留了,以致延誤到連線釋放後的某個時間才到達B。本來這是一個早已失效的報文段。但B收到此失效的連線請求報文段後,卻誤以為是A又發出一次新的連線請求,於是就向A發出確認報文段,同意建立連線。

由於現在A並沒有發出建立連線的請求,因此不會理睬B的確認,也不會向B傳送資料,但B卻以為新的運輸連線已經建立了,並一直等待A發來的資料。B的許多資源就這樣白白浪費了。

2。兩個TCP建立請求相互之間同時發起時會發生什麼?建立幾個連線?

首先理解題意,我們知道三次握手正是建立TCP連線的過程,我們假設 A 是客戶端,B 是服務端:

HTTP 三次握手 四次揮手

rfc793-同時啟動

這裡先給大家講一下上圖中一些符號的含義:

右箭頭 (——>) :從 A 傳送到 B 的 TCP 報文段,且 B 接收到了;

左箭頭 (<——) :從 B 傳送到 A 的 TCP 報文段,且 A 接收到了;

省略號 (…) :TCP 報文段仍在網路中(delayed);

丟失 (“XXX”) :TCP 報文段丟失或者被拒絕。

註釋會放在括號中;

TCP 狀態代表了處於中間的報文段到達之後的狀態(AFTER);

報文段的內容只顯示了序列號(SEQ)、控制符(CTL)和 ACK,其餘內容被省略。

接下來我們詳細來看看上圖中,兩個請求

同時相互發起

時,兩個TCP均會經歷如下狀態的轉換:

HTTP 三次握手 四次揮手

同步請求的狀態轉換

上述的狀態轉換圖可以跟前面的三次握手的轉換圖進行對比理解,同時發起的兩個請求最終只會建立一個連線。

SYN-RECEIVED 跟 SYN-RCVD是一樣的,前者rcf793中的描述方法,後者是《計算機網路-自頂向下方法》中的使用方法。

3。 客戶端正在和服務端建立 TCP 連線,然而當伺服器變 SYN-RCVD 後,此時一箇舊的 SYN 報文 又到達了,伺服器會如何處理?

其實這道題更加深挖了TCP 建立連線的過程,我們可以在rfc793中瞭解到詳細資訊。

HTTP 三次握手 四次揮手

rfc793-RST

從上圖可以看到,第三行就是舊的SYN 連線到達伺服器時,第四行是伺服器照常返回,第五行是客戶端給服務端傳送RST 報文,將服務端重置為LISTEN。

我們需要從上圖瞭解到的一點是,服務端在SYN_RECEIVED狀態下,接收到舊的SYN 報文時是

不能作出判斷

的,而是照常返回,當客戶端接收到該報文後發現異常,才會傳送RST 報文,重置連線。

關於RST 報文,我一開始也很疑惑,直到看到rfc793 原文:

HTTP 三次握手 四次揮手

rfc793-page33

確實說明了TCP B不能檢測這個舊的SYN 報文是否正確,所以正常返回。而客戶端收到會進行檢測,發現是舊的報文,就會返回RST 報文。

4。第三次握手失敗了怎麼辦?

這個問題在網上找到的答案質量參差不齊,翻閱了rfc793,仔細研究後,最終整理出以下答案:

首先考慮失敗的情況:

HTTP 三次握手 四次揮手

ACK報文丟失導致第三次握手失敗

當客戶端收到服務端的SYNACK應答後,其狀態變為ESTABLISHED,並會發送ACK包給服務端,準備傳送資料了。如果此時ACK在網路中丟失(如上圖所示),過了超時計時器後,那麼服務端會重新發送SYNACK包,重傳次數根據/proc/sys/net/ipv4/tcp_synack_retries來指定,預設是5次。如果重傳指定次數到了後,仍然未收到ACK應答,那麼一段時間後,Server自動關閉這個連線。

問題就在這裡,客戶端已經認為連線建立,而服務端則可能處在SYN-RCVD或者CLOSED,接下來我們需要考慮這兩種情況下服務端的應答:

服務端處於CLOSED,當接收到連線已經關閉的請求時,服務端會返回RST 報文,客戶端接收到後就會關閉連線,如果需要的話則會重連,那麼那就是另一個三次握手了。

服務端處於SYN-RCVD,此時如果接收到正常的ACK 報文,那麼很好,連線恢復,繼續傳輸資料;如果接收到寫入資料等請求呢?注意了,此時寫入資料等請求也是帶著ACK 報文的,實際上也能恢復連線,使伺服器恢復到ESTABLISHED狀態,繼續傳輸資料。

這個結論也可以在STACKFLOW上找到驗證:

HTTP 三次握手 四次揮手

What if a TCP handshake segment is lost?

上圖圈住的部分:

總的來說,如果一個ACK 報文丟失了,但它的下一個資料包沒有丟失,那麼連線正常,否則,連線會被重置。

5。知道SYN攻擊嗎?如何防範?

所謂SYN 洪泛攻擊,就是利用SYNACK 報文的時候,伺服器會為客戶端請求分配快取,那麼駭客(攻擊者),就可以使用一批虛假的ip向伺服器大量地發建立TCP 連線的請求,伺服器為這些虛假ip分配了快取後,處在SYN_RCVD狀態,存放在半連線佇列中;另外,伺服器傳送的請求又不可能得到回覆(ip都是假的,能回覆就有鬼了),只能不斷地重發請求,直到達到設定的時間/次數後,才會關閉。

伺服器不斷為這些半開連線分配資源(但從未使用),導致伺服器的連線資源被消耗殆盡,不過所幸,我們可以使用SYN Cookie進行有效地防禦。

所謂的SYN Cookie防禦系統,與前面接收到SYN 報文就分配快取不同,此時暫不分配資源;同時利用SYN 報文的源和目的地IP和埠,以及伺服器儲存的一個秘密數,使用它們進行雜湊,得到server_isn,然後附著在SYNACK 報文中傳送給客戶端,接下來就是對ACK 報文進行判斷,如果其返回的ack欄位正好等於server_isn + 1,說明這是一個合法的ACK,那麼伺服器才會為其生成一個具有套接字的全開的連線。

HTTP 三次握手 四次揮手

SYN Cookie 防禦

當然這種方案也有一定缺點,最明顯的就是伺服器不儲存連線的半開狀態,就喪失了重發SYN-ACK訊息的能力,這一方面會降低正常使用者的連線成功率,另一方面會導致某些情況下正常通訊的雙方會對連線是否成功開啟產生誤解,如客戶端發給服務端的第三次握手訊息(ACK)半路遺失,客戶端認為連線成功了,服務端認為沒收到ACK,連線沒成功,這種情況就需要上層應用採取策略特別處理了。

6。(ISN)是固定的嗎?

不固定,client_isn是隨機生成的,而server_isn則需要根據SYN 報文中的源、ip和埠,加上伺服器本身的密碼數進行相同的雜湊得到,顯然這也不是固定的。

7。三次握手過程中可以攜帶資料嗎?

講過程的時候其實已經講了,第三次握手是可以攜帶資料的,而前兩次不行。

8。 關於 https 的認證過程?

限於篇幅,此處暫時不講,留意後續文章。

四次揮手

和握手類似,每次揮手也代表一次報文的發出和接收。

過程描述

因為自頂向上這本書裡面的圖比較簡略,這裡採用謝希仁版本的計算機網路中的圖:

HTTP 三次握手 四次揮手

計算機網路-謝希仁-四次揮手

首先,當前客戶端和伺服器的狀態都為ESTABLISHED,接下來我們詳細講解下上圖的過程:

客戶主機發起連線釋放的請求,設定FIN為1,當然,序號seq也會帶上,這裡假設為u;傳送完畢後,客戶端進入 FIN-WAIT-1 狀態。

HTTP 三次握手 四次揮手

第一次揮手:FIN報文

服務端接收到FIN 報文後,會返回一個ACK 報文回去,此時設定ACK為1,確認號為u + 1;表明自己接受到了客戶端關閉連線的請求,但還沒有準備好關閉連線。傳送完畢後,伺服器端進入 CLOSE-WAIT 狀態,客戶端接收到這個確認包之後,進入 FIN-WAIT-2 狀態,等待伺服器端關閉連線。

HTTP 三次握手 四次揮手

第二次揮手:ACK報文

伺服器端準備好關閉連線時,向客戶端傳送結束連線請求,FIN 置為1;傳送完畢後,伺服器端進入 LAST-ACK 狀態,等待來自客戶端的最後一個ACK。

HTTP 三次握手 四次揮手

第三次揮手:FIN報文

客戶端接收到服務端傳來的FIN 報文後,知道伺服器已經準備好關閉了,傳送一個確認包,並進入 TIME-WAIT狀態,等待可能出現的要求重傳的ACK 報文;伺服器端接收到這個確認包之後,關閉連線,進入 CLOSED 狀態。

客戶端等待了某個固定時間(兩個最大段生命週期,2MSL,2 Maximum Segment Lifetime)之後,沒有收到伺服器端的 ACK ,認為伺服器端已經正常關閉連線,於是自己也關閉連線,進入 CLOSED 狀態。

HTTP 三次握手 四次揮手

第四次揮手:ACK報文

這裡我們再來看下rfc793中關於四次揮手的簡單例子:

HTTP 三次握手 四次揮手

rfc793-正常的關閉例子

細節拓展

四次揮手重要的是TIME-WAIT狀態,為什麼需要這個狀態呢?

要確保伺服器是否已經收到了我們的ACK 報文,如果沒有收到的話,伺服器會重新發FIN 報文給客戶端,那麼客戶端再次收到FIN 報文之後,就知道之前的 ACK 報文丟失了,就會再次傳送ACK 報文。

問題深究

1。為什麼握手只要三次,揮手卻要四次?

關鍵就在中間兩步。

建立連線時,當伺服器收到客戶端的SYN 報文後,可以直接傳送SYNACK 報文。其中ACK是用來應答的,SYN是用來同步的。

但是關閉連線時,當伺服器收到FIN 報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK 報文,告訴客戶端,“你發的FIN 報文我收到了”。只有等到伺服器所有的報文都發送/接收完了,我才能傳送FIN 報文,因此不能一起傳送,需要四次握手。

2。為什麼 TIME_WAIT 狀態需要經過 2MSL 才能轉換到 CLOSE 狀態?

第一,為了保證客戶端傳送的最後一個ACK 報文能夠到達伺服器。我們必須假設網路是不可靠的,ACK 報文可能丟失。如果服務端發出FIN 報文後沒有收到ACK 報文,就會重發FIN 報文,此時處於TIME-WAIT狀態的客戶端就會重發ACK 報文。當然,客戶端也不能無限久的等待這個可能存在的FIN 報文,因為如果服務端正常接收到了ACK 報文後是不會再發FIN 報文的。因此,客戶端需要設定一個計時器,那麼等待多久最合適呢?所謂的MSL(Maximum Segment Lifetime)指一個報文在網路中最大的存活時間,2MSL就是

一個傳送和一個回覆所需的最大時間

。如果直到2MSL時間後,客戶端都沒有再次收到FIN 報文,那麼客戶端推斷ACK 報文已經被伺服器成功接收,所以結束TCP 連線。

第二,防止

已失效的連線請求報文段

出現在新的連線中。客戶端在傳送完最後一個ACK 報文後,再經過時間2MSL,就可以使由於網路不通暢產生的滯留報文段失效。這樣下一個新的連線中就不會出現舊的連線請求報文。

Top