詳解 TCP 三次握手、四次揮手,附帶精美圖解和超高頻面試題

1、TCP 報文段簡介

在介紹三次握手和四次揮手以前,先來簡單認識一下 TCP 報文段的結構
報文段結構.png
TCP 首部包含如下內容,請留意其中的控制位,在三次握手和四次揮手過程當中會頻繁出現:面試

  • 端口號 (Source Port and Destination Port):每一個 TCP 報文段都包含源端和目的端的端口號,用於尋找發送端和接收端應用進程。這兩個值加上 IP 首部中的源端 IP 地址和目的端 IP 地址就能夠肯定一個惟一的 TCP 鏈接。
  • 序號 (Sequence Number):這個字段的主要做用是用於將失序的數據從新排列。TCP 會隱式地對字節流中的每一個字節進行編號,而 TCP 報文段的序號被設置爲其數據部分的第一個字節的編號。序號是 32 bit 的無符號數,取值範圍是0到 232 - 1。
  • 確認序號 (Acknowledgment Number):接收方在接受到數據後,會回覆確認報文,其中包含確認序號,做用就是告訴發送方本身接收到了哪些數據,下一次數據從哪裏開始發,所以,確認序號應當是上次已成功收到數據字節序號加 1。只有 ACK 標誌爲 1 時確認序號字段纔有效。
  • 首部長度 (Header Length):首部中的選項部分的長度是可變的,所以首部的長度也是可變的,因此須要這個字段來明確表示首部的長度,這個字段佔 4 bit,4 位的二進制數最大能夠表示 15,而首部長度是以 4 個字節爲一個單位的,所以首部最大長度是 15 * 4 = 60 字節。
  • 保留字段 (Reserved):佔 6 位,將來可能有具體用途,目前默認值爲0.
  • 控制位 (Control Bits):在三次握手和四次揮手中會常常看到 SYN、ACK 和 FIN 的身影,一共有 6 個標誌位,它們表示的意義以下:算法

    • URG (Urgent Bit):值爲 1 時,緊急指針生效
    • ACK (Acknowledgment Bit):值爲 1 時,確認序號生效
    • PSH (Push Bit):接收方應儘快將這個報文段交給應用層
    • RST (Reset Bit):發送端遇到問題,想要重建鏈接
    • SYN (Synchronize Bit):同步序號,用於發起一個鏈接
    • FIN (Finish Bit):發送端要求關閉鏈接
  • 窗口大小 (Window): TCP的流量控制由鏈接的每一端經過聲明的窗口大小來提供。窗口大小爲字節數,起始於確認序號字段指明的值,這個值是接收端正指望接收的字節。窗口大小是一個 16 bit 字段,單位是字節, 於是窗口大小最大爲 65535 字節。
  • 檢驗和 (Checksum):功能相似於數字簽名,用於驗證數據完整性,也就是確保數據未被修改。檢驗和覆蓋了整個 TCP 報文段,包括 TCP 首部和 TCP 數據,發送端根據特定算法對整個報文段計算出一個檢驗和,接收端會進行計算並驗證。
  • 緊急指針 (Urgent Pointer):當 URG 控制位值爲 1 時,此字段生效,緊急指針是一個正的偏移量,和序號字段中的值相加表示緊急數據最後一個字節的序號。 TCP 的緊急方式是發送端向另外一端發送緊急數據的一種方式。
  • 選項 (Options):這一部分是可選字段,也就是非必須字段,最多見的可選字段是「最長報文大小 (MSS,Maximum Segment Size)」。
  • 有效數據部分 (Data):這部分也不是必須的,好比在創建和關閉 TCP 鏈接的階段,雙方交換的報文段就只包含 TCP 首部。

2、TCP 的鏈接控制

2.1 創建鏈接

2.1.1 三次握手

這個問題簡直太經典了,若是你在面試中只被問到了一個關於 TCP 的問題,那大機率就是關於三次握手的問題。TCP 的重要特性之一就是面向鏈接,鏈接雙方在發送數據以前必須經歷握手的階段,那具體的過程是怎樣的呢?先來看圖,你們最好能夠動手簡單畫畫這個圖,固然還有後文四次揮手的圖,幫助加深記憶。緩存

三次握手過程.png

三次握手過程

如圖所示,雙方之間的三個藍色箭頭就表示了三次握手過程當中所發生的數據交換:服務器

  1. 第一次握手:客戶端向服務器發送報文段1,其中的 SYN 標誌位 (前文已經介紹過各類標誌位的做用)的值爲 1,表示這是一個用於請求發起鏈接的報文段,其中的序號字段 (Sequence Number,圖中簡寫爲seq)被設置爲初始序號x (Initial Sequence Number,ISN),TCP 鏈接雙方都可隨機選擇初始序號。發送完報文段1以後,客戶端進入 SYN-SENT 狀態,等待服務器的確認。
  2. 第二次握手:服務器在收到客戶端的鏈接請求後,向客戶端發送報文段2做爲應答,其中 ACK 標誌位設置爲 1,表示對客戶端作出應答,其確認序號字段 (Acknowledgment Number,圖中簡寫爲小寫 ack) 生效,該字段值爲 x + 1,也就是從客戶端收到的報文段的序號加一,表明服務器指望下次收到客戶端的數據的序號。此外,報文段2的 SYN 標誌位也設置爲1,表明這同時也是一個用於發起鏈接的報文段,序號 seq 設置爲服務器初始序號y。發送完報文段2後,服務器進入 SYN-RECEIVED 狀態。
  3. 第三次握手:客戶端在收到報文段2後,向服務器發送報文段3,其 ACK 標誌位爲1,表明對服務器作出應答,確認序號字段 ack 爲 y + 1,序號字段 seq 爲 x + 1。此報文段發送完畢後,雙方都進入 ESTABLISHED 狀態,表示鏈接已創建。

常見面試題 1: TCP 創建鏈接爲何要三次握手而不是兩次?cookie

答:網上大多數資料對這個問題的回答只有簡單的一句:防止已過時的鏈接請求報文忽然又傳送到服務器,於是產生錯誤,這既不夠全面也不夠具體。下面給出比較詳細而全面的回答:網絡

  1. 防止已過時的鏈接請求報文忽然又傳送到服務器,於是產生錯誤

    在雙方兩次握手便可創建鏈接的狀況下,假設客戶端發送 A 報文段請求創建鏈接,因爲網絡緣由形成 A 暫時沒法到達服務器,服務器接收不到請求報文段就不會返回確認報文段,客戶端在長時間得不到應答的狀況下從新發送請求報文段 B,此次 B 順利到達服務器,服務器隨即返回確認報文並進入 ESTABLISHED 狀態,客戶端在收到 確認報文後也進入 ESTABLISHED 狀態,雙方創建鏈接並傳輸數據,以後正常斷開鏈接。此時姍姍來遲的 A 報文段纔到達服務器,服務器隨即返回確認報文並進入 ESTABLISHED 狀態,可是已經進入 CLOSED 狀態的客戶端沒法再接受確認報文段,更沒法進入 ESTABLISHED 狀態,這將致使服務器長時間單方面等待,形成資源浪費。併發

  2. 三次握手才能讓雙方均確認本身和對方的發送和接收能力都正常

    第一次握手:客戶端只是發送處請求報文段,什麼都沒法確認,而服務器能夠確認本身的接收能力和對方的發送能力正常;函數

    第二次握手:客戶端能夠確認本身發送能力和接收能力正常,對方發送能力和接收能力正常;spa

    第三次握手:服務器能夠確認本身發送能力和接收能力正常,對方發送能力和接收能力正常;操作系統

    可見三次握手才能讓雙方都確認本身和對方的發送和接收能力所有正常,這樣就能夠愉快地進行通訊了。

  3. 告知對方本身的初始序號值,並確認收到對方的初始序號值

    TCP 實現了可靠的數據傳輸,緣由之一就是 TCP 報文段中維護了序號字段和確認序號字段,也就是圖中的 seq 和 ack,經過這兩個字段雙方均可以知道在本身發出的數據中,哪些是已經被對方確認接收的。這兩個字段的值會在初始序號值得基礎遞增,若是是兩次握手,只有發起方的初始序號能夠獲得確認,而另外一方的初始序號則得不到確認。

常見面試題2: TCP 創建鏈接爲何要三次握手而不是四次?

答:相比上個問題而言,這個問題就簡單多了。由於三次握手已經能夠確認雙方的發送接收能力正常,雙方都知道彼此已經準備好,並且也能夠完成對雙方初始序號值得確認,也就無需再第四次握手了。

常見面試題3: 有一種網絡攻擊是利用了 TCP 創建鏈接機制的漏洞,你瞭解嗎?這個問題怎麼解決?

答:在三次握手過程當中,服務器在收到了客戶端的 SYN 報文段後,會分配並初始化鏈接變量和緩存,並向客戶端發送 SYN + ACK 報文段,這至關因而打開了一個「半開鏈接 (half-open connection)」,會消耗服務器資源。若是客戶端正常返回了 ACK 報文段,那麼雙方能夠正常創建鏈接,不然,服務器在等待一分鐘後會終止這個「半開鏈接」並回收資源。這樣的機制爲 SYN洪泛攻擊 (SYN flood attack)提供了機會,這是一種經典的 DoS攻擊 (Denial of Service,拒絕服務攻擊),所謂的拒絕服務攻擊就是經過進行攻擊,使受害主機或網絡不能提供良好的服務,從而間接達到攻擊的目的。在 SYN 洪泛攻擊中,攻擊者發送大量的 SYN 報文段到服務器請求創建鏈接,可是卻不進行第三次握手,這會致使服務器打開大量的半開鏈接,消耗大量的資源,最終沒法進行正常的服務。

解決方法:SYN Cookies,如今大多數主流操做系統都有這種防護系統。SYN Cookies 是對 TCP 服務器端的三次握手作一些修改,專門用來防範 SYN 洪泛攻擊的一種手段。它的原理是,在服務器接收到 SYN 報文段並返回 SYN + ACK 報文段時,再也不打開一個半開鏈接,也不分配資源,而是根據這個 SYN 報文段的重要信息 (包括源和目的 IP 地址,端口號可一個祕密數),利用特定散列函數計算出一個 cookie 值。這個 cookie 做爲將要返回的SYN + ACK 報文段的初始序列號(ISN)。當客戶端返回一個 ACK 報文段時,服務器根據首部字段信息計算 cookie,與返回的確認序號(初始序列號 + 1)進行對比,若是相同,則是一個正常鏈接,而後分配資源並創建鏈接,不然拒絕創建鏈接。

2.2.2 同時打開

這是 TCP 創建鏈接的特殊狀況,有時會出現兩臺機器同時執行主動打開的狀況,不過幾率很是小,這種狀況你們僅做了解便可。在這種狀況下就無所謂發送方和接收方了,雙放均可以稱爲客戶端和服務器,同時打開的過程以下:

同時打開.png

同時打開的過程

如圖所示,雙方在同一時刻發送 SYN 報文段,並進入 SYN-SENT 狀態,在收到 SYN 後,狀態變爲 SYN-RECEIVED,同時它們都再發送一個 SYN + ACK 的報文段,狀態都變爲 ESTABLISHED,鏈接成功創建。在此過程當中雙方一共交換了4個報文段,比三次握手多一個。

2.2 關閉鏈接

2.2.1 四次揮手

創建一個鏈接須要三次握手,而終止一個鏈接要通過 4次握手。這由 TCP 的半關閉( half-close) 形成的。既然一個 TCP 鏈接是全雙工 (即數據在兩個方向上能同時傳遞), 所以每一個方向必須單獨地進行關閉。這原則就是當一方完成它的數據發送任務後就能發送一個 FIN 來終止這個方向鏈接。當一端收到一個 FIN,它必須通知應用層另外一端已經終止了數據傳送。理論上客戶端和服務器均可以發起主動關閉,可是更多的狀況下是客戶端主動發起。

四次揮手過程.png

四次揮手過程

四次揮手詳細過程以下:

  1. 客戶端發送關閉鏈接的報文段,FIN 標誌位1,請求關閉鏈接,並中止發送數據。序號字段 seq = x (等於以前發送的全部數據的最後一個字節的序號加一),而後客戶端會進入 FIN-WAIT-1 狀態,等待來自服務器的確認報文。
  2. 服務器收到 FIN 報文後,發回確認報文,ACK = 1, ack = x + 1,並帶上本身的序號 seq = y,而後服務器就進入 CLOSE-WAIT 狀態。服務器還會通知上層的應用程序對方已經釋放鏈接,此時 TCP 處於半關閉狀態,也就是說客戶端已經沒有數據要發送了,可是服務器還能夠發送數據,客戶端也還可以接收。
  3. 客戶端收到服務器的 ACK 報文段後隨即進入 FIN-WAIT-2 狀態,此時還能收到來自服務器的數據,直到收到 FIN 報文段。
  4. 服務器發送完全部數據後,會向客戶端發送 FIN 報文段,各字段值如圖所示,隨後服務器進入 LAST-ACK 狀態,等待來自客戶端的確認報文段。
  5. 客戶端收到來自服務器的 FIN 報文段後,向服務器發送 ACK 報文,隨後進入 TIME-WAIT 狀態,等待 2MSL(2 * Maximum Segment Lifetime,兩倍的報文段最大存活時間) ,這是任何報文段在被丟棄前能在網絡中存在的最長時間,經常使用值有30秒、1分鐘和2分鐘。如無特殊狀況,客戶端會進入 CLOSED 狀態。
  6. 服務器在接收到客戶端的 ACK 報文後會隨即進入 CLOSED 狀態,因爲沒有等待時間,通常而言,服務器比客戶端更早進入 CLOSED 狀態。

常見面試題1: 爲何 TCP 關閉鏈接爲何要四次而不是三次?

答:服務器在收到客戶端的 FIN 報文段後,可能還有一些數據要傳輸,因此不能立刻關閉鏈接,可是會作出應答,返回 ACK 報文段,接下來可能會繼續發送數據,在數據發送完後,服務器會向客戶單發送 FIN 報文,表示數據已經發送完畢,請求關閉鏈接,而後客戶端再作出應答,所以一共須要四次揮手。

常見面試題2: 客戶端爲何須要在 TIME-WAIT 狀態等待 2MSL 時間才能進入 CLOSED 狀態?

答:按照常理,在網絡正常的狀況下,四個報文段發送完後,雙方就能夠關閉鏈接進入 CLOSED 狀態了,可是網絡並不老是可靠的,若是客戶端發送的 ACK 報文段丟失,服務器在接收不到 ACK 的狀況下會一直重發 FIN 報文段,這顯然不是咱們想要的。所以客戶端爲了確保服務器收到了 ACK,會設置一個定時器,並在 TIME-WAIT 狀態等待 2MSL 的時間,若是在此期間又收到了來自服務器的 FIN 報文段,那麼客戶端會從新設置計時器並再次等待 2MSL 的時間,若是在這段時間內沒有收到來自服務器的 FIN 報文,那就說明服務器已經成功收到了 ACK 報文,此時客戶端就能夠進入 CLOSED 狀態了。

2.2.2 同時關閉

以前在介紹 TCP 創建鏈接的時候會有一種特殊狀況,那就是同時打開,與之對應地, TCP 關閉時也會有一種特殊狀況,那就是同時關閉,這種狀況僅做了解便可,流程圖以下:

同時關閉過程.png

同時關閉過程

這種狀況下,雙方應用層同時發出關閉命令,這將致使雙方各發送一個 FIN,兩端均從 ESTABLISHED 變爲 FIN_WAIT_1,兩個 FIN 通過網絡傳送後分別到達另外一端。收到 FIN 後,狀態由 FIN_WAIT_1 變遷到 CLOSING,併發送最後的 ACK,當收到最後的 ACK 時,爲確保對方也收到 ACK,狀態變化爲 TIME_WAIT,並等待 2MSL 時間,若是一切正常,隨後會進入 CLOSED 狀態。

總結

本文經過圖解的方式爲你們詳細介紹了 TCP 三次握手和四次揮手的過程,只要把這幾張圖弄明白,再碰到相關的面試題就遊刃有餘了。

相關文章
相關標籤/搜索