一文串聯 HTTP、TCP、IP、以太網

最近部門組織了一次前端性能優化交流會,你們從輸入頁面 URL 到最終頁面展現內容這個過程提出了許多優化點。但同時發現不少同窗對 HTTP 協議層的知識不能串聯起來,因而整理了這篇文章,但願能夠給你們帶來一絲靈感。javascript

當咱們在頁面上發起一個 AJAX 請求的時候,在網絡協議層面都經歷了哪些內容?前端

// 發起請求
fetch('https://baidu.com')
// 協議層1...
// 協議層2...
// 協議層3...
.then(res=>
  // 獲得結果
  console.log(res)
})

如上述代碼所示,咱們對 baidu.com 發起了一個網絡請求,最終在 then 方法中獲得了具體的響應內容。java

使用 Wireshark 抓包結果以下:算法

圖中能夠看到,請求 baidu.com 時,首先經過 TCP 3 次握手創建鏈接,而後經過 HTTP 傳輸內容,最後經過 TCP 4 次揮手斷開鏈接。瀏覽器

真實的過程更加複雜,咱們主要分析如下幾點:緩存

  • 創建鏈接階段安全

    • DNS 域名解析(應用層)
    • 創建 TCP 鏈接(傳輸層)性能優化

      • 經過 IP 尋址找到目標服務器(網絡層)
      • 經過 Mac 尋址找到服務器硬件接口(數據鏈路層)
      • 經過網線向服務器硬件接口傳輸比特信息(物理層)
  • 發送數據階段服務器

    • 創建 SSL 安全鏈接(應用層)
    • 發送 HTTP 請求(應用層)

創建鏈接階段

要獲取 baidu.com 的網頁內容,就須要和 baidu 服務器創建鏈接,怎樣創建這個鏈接呢?網絡

  1. 經過 DNS 獲取 baidu 的 IP 地址。
  2. 創建 TCP 鏈接。

DNS 域名解析

經過 DNS 解析,咱們就能找到 baidu 服務器對應的 IP 地址。

如圖:

通過 DNS 解析後,咱們就能獲得 baidu.com 的 IP 地址了:39.156.69.79 和 220.181.38.148,一般客戶端會隨機選中一個 IP 地址進行通訊。

域名的解析步驟

其實 IP 不必定要經過 DNS 解析才能獲取,它一般會被客戶端緩存,只有在 DNS 緩存都沒有命中的時候纔會請求 DNS 服務器。

判斷步驟以下:

  1. 判斷瀏覽器是否有緩存 IP 地址。
  2. 判斷本機是否有緩存該 IP 地址,如:檢查 Host 文件。
  3. 判斷本地域名解析服務器是否有緩存 IP 地址,如:電信,聯通等運營商。
  4. 向 DNS 根域名解析服務器,解析域名 IP 地址。
  5. 向 DNS 二根域名解析服務器,解析域名 IP 地址。
  6. 以此類推,最終得到 IP 地址。

創建 TCP 鏈接

有了 IP 地址以後,客戶端和服務器端就能創建鏈接了,首先是創建 TCP 鏈接。

TCP 是一種面向鏈接的、可靠的、基於字節流的傳輸層通訊協議。

在這一層,咱們傳輸的數據會按照一個個的字節裝入報文中,當報文的長度達到最大分段(MSS)時,就會發送這個報文。若是傳輸的報文很長,可能會被拆分紅多個 TCP 報文進行傳輸。

TCP 報文頭以下:

咱們主要看如下幾點:

  • 源端口、目的端口。
  • 序列號:seq,報文的惟一標識。
  • 確認號:ack,報文的確認標識,便於確認 seq 是否已經收到。
  • TCP 標記:

    • SYN 爲 1 表示這是鏈接請求或是鏈接接受請求。用於建立鏈接和同步序列號。
    • ACK 爲 1 表示確認號字段有效。注意這裏大寫的 ACK 只是一個標記,和確認號 ack 並不相同。
    • FIN 爲 1 表示要求釋放鏈接。
  • 窗口:表示發送方能夠接收的字節數,即接收窗口大小,用於流量控制。

接下來,咱們看一下 TCP 是怎樣創建鏈接的?

如圖所示,創建 TCP 鏈接須要 3 個步驟,俗稱三次握手。

  • 第一次握手:客戶端向服務器端發送序列號 seq=x 的標識,表示開始創建鏈接。
  • 第二次握手:服務器端回發一個 ack=x+1 的標識,表示確認收到第一次握手,同時發送本身的標識 seq=y。

    • 客戶端確認本身發出的數據可以被服務器端收到。
  • 第三次握手:客戶端發送 ack=y+1 的標識,標識確認收到第二次握手。

    • 服務器端確認本身發出的數據可以被客戶端收到。

通過了 3 次握手,即保證了客戶端和服務器端都能正常發送和接收數據,TCP 鏈接也就創建成功了。

TCP 可靠傳輸原理

上文中說到,TCP 是可靠的傳輸,這是爲何呢?

這是由於 TCP 內部使用了 中止等待協議 ARQ ,它經過 確認重傳 機制,實現了信息的可靠傳輸。

例如:

  • 客戶端發送數據 M1
  • 服務器端確認數據 M1 收到
  • 客戶端發送數據 M2
  • 服務器端確認數據 M2 收到
  • 依次類推 ...

在這期間,若是某一條數據好久都沒有獲得確認,客戶端就會重傳這條數據。這樣一來,對於與每一次發送的數據,服務器端都獲得了確認,即保證了數據的可靠性。

雖然 ARQ 能夠知足數據可靠性,但每次只能發送和確認一個請求,效率過低了,因而就產生了連續 ARQ 協議。

連續 ARQ 協議 會連續發送一組數據,而後再批量等待這一組數據的確認信息,比如把單線程 ARQ 變成了多線程,大大提升了資源的利用效率。

如:

  • 客戶端發送數據 M一、M二、M三、M4。
  • 服務器端確認數據 M4 收到,表示 M4 及以前的數據都收到了。
  • 客戶端發送數據 M五、M六、M七、M8。
  • 服務器端確認數據 M8 收到,表示 M8 及以前的數據都收到了。

在這個流程中,服務器端不須要對每個數據都返回確認信息,而是接收到多個數據時一併確認,這個方式叫作 累計確認


這裏有個疑問,TCP 的每一次握手,是怎麼找到目的服務器呢?

答:經過 IP 協議。

根據 IP 協議找到目標服務器

IP 協議的目的是實現網絡層的數據轉發,它經過路由器不斷跳轉,最終把數據成功送達目的地。

上文中的每一次 TCP 握手以及數據交互,都是經過 IP 協議去傳輸的。

IP 報文頭以下:

咱們關注如下兩點就能夠了:

  • 源 IP 地址
  • 目的 IP 地址

發起一個 IP 請求執行流程以下:

  1. 構建 IP 請求頭(源 IP、目標 IP)。
  2. IP 協議經過算法,計算出一條通往服務器端的路徑。
  3. 發送端查詢路由表,找出下一跳的 IP 地址(一般是路由器),併發送數據。
  4. 路由器查詢路由表,找出下一跳的 IP 地址,併發送數據。
  5. 不斷重複步驟 4,直到找到目的局域網。
  6. 發送數據。
路由表存在於計算機或路由器中,由目的 IP 地址、子網掩碼、下一跳地址、發送接口四部分組成。經過目的 IP 地址,便可找到下一跳的地址,進行轉發。

例如:A 要向 G 發送 IP 數據。

具體流程以下:

  • A 生成 IP 頭部(源 IP:A ,目的 IP:G)

    • A 查詢路由表,發現下一跳爲 B,因而把數據傳給 B。
  • B 生成 IP 頭部(源 IP:A ,目的 IP:G)

    • B 查詢路由表,發現下一跳爲 E,因而把數據傳給 E。
  • E 生成 IP 頭部(源 IP:A ,目的 IP:G)

    • E 查詢路由表,發現下一跳爲 G,因而把數據傳給 G。
  • 到達目的地 G。

你是否有疑惑,爲何 IP 會按照這條路徑向 G 傳輸數據呢?

其實,上圖中的路徑並不是只有一條,咱們經過 ABEG 到達了目的地 G,一樣也能夠經過 ABCFHG 到達 G,這兩種路徑都能完成任務,爲何 IP 不選擇 ABCFHG 這條路徑呢?

這就涉及到了 IP 尋址的算法。

IP 尋址算法

咱們能夠把網絡中的全部計算機都看作是一個點,計算機之間的鏈接看作是一條線,這些點和線就組合成了一個圖。

例如:

經過上圖,咱們就把複雜的網絡轉化成了數學問題。IP 尋址算法,其實就是圖論中的最短路徑的算法。

最短路徑算法在 IP 協議中有 2 種實現:

  • RIP 協議

    • 使用距離矢量算法,確保 IP 路由跳轉的次數最小
    • 原理

      • 每一個節點中都保存有其餘節點的位置信息(跳數和下一跳的 IP)。
      • 經過和鄰居節點進行數據交換,更新本身到目的地的最短距離,不斷重複,便可獲得起點到終點的最短路徑。
      • 實現簡單,開銷很小,適用於小型網絡。
  • OSPF 協議

    • 使用迪傑斯特拉算法,確保 IP 路由跳轉的速度最快
    • 原理

      • 從起始點開始,採用貪心算法的策略,每次遍歷到始點距離最近且未訪問過的頂點的鄰接節點,直到擴展到終點爲止。
      • 適用於大型網絡。

經過以上兩個協議,咱們就能找到通往目的地的路徑了。


這裏拋出一個問題:IP 數據是怎樣從一個路由器跳到另外一個路由器呢?

答:經過以太網協議。

經過 Mac 尋址找到服務器硬件接口

IP 協議主要是用來尋找最優路徑的,具體的傳輸是由以太網協議來作的。

以太網屬於數據鏈路層,它主要負責相鄰設備的通訊。原理是經過查詢交換機 Mac 表,找到通訊雙方的物理接口,進而開始通訊。

以太網報文頭以下:

咱們只用關心如下 3 個點:

  • 源 Mac 地址
  • 目的 Mac 地址
  • 校驗碼 CRC:校驗當前幀是否有效。

能夠看到,以太網層都是經過 Mac 地址進行通訊的,這裏的 Mac 地址是哪裏來的呢?

答:經過 ARP 協議。

ARP 協議 是一個經過解析 IP 地址來找尋 Mac 地址的協議。IP 地址轉換成 Mac 地址後,就能進行以太網數據傳輸了。

例如:

當機器 A 向機器 C 發送數據時:

  • A 構建以太網報文(源地址:A,目的地址:C),並經過網卡發出數據幀。
  • 數據幀到達交換機 B,交換機取出目的地址 C 的 Mac 地址。
  • B 查詢 Mac 表,根據目的地 Mac 地址,匹配 C 的硬件接口。

    • 若是找到 C 的硬件接口,發送數據。
    • 若是未找到 C 的硬件接口,向 B 直連的全部機器發送廣播信息找 C,找到後會把 C 記錄到 Mac 表中。

通過上述的流程,咱們就找到了目的機器的硬件接口。


經過以太網協議,咱們找到了目標機器的硬件接口,接下來要怎麼發送信息呢?

答:經過物理層。

經過網線向服務器硬件接口傳輸比特信息

在沒有 WiFi 的年代,咱們只能經過插網線來進行上網,網線其實就是物理層的設備之一。

網線能夠由多種材料組成,最多見的就是光纖和電纜。

光纖和電纜的傳輸原理相似,都是經過兩個信號來模擬二進制數據的,一個信號即爲一個比特。

  • 電纜中:高電位表示 1 ,低點位表示 0。
  • 光纖中:光亮表示 1,光熄滅表示 0。

如:在光纖中,咱們經過觀察光的閃動,便可得知傳輸的二進制數據。

有了這些物理設備,咱們就能把複雜的數據轉換成光信號或者電信號進行傳輸了。

發送數據階段

發送數據能夠分爲兩個步驟:

  • 創建安全層 SSL
  • 發送 HTTP 請求

創建安全層 SSL

本文的案例是發送一個 HTTPS 的請求,因此在發送數據以前,會建立一個 SSL 安全層,用於數據加密。

一般的加密方法有兩種:

  • 非對稱加密

    • A 有鑰匙,B 沒有鑰匙,且他們都有一個公共的鎖,B 給 A 發送數據時,都會先把數據鎖起來再發送。
    • 接收數據時,A 用鑰匙解開鎖,便可獲得數據。除 A 之外,其餘人沒有鑰匙,也就獲取不到數據。
    • 實現了單向通訊加密。
  • 對稱加密

    • A、B 雙方都有一把相同的鑰匙和一個公共的鎖,每次發送數據時,都把數據放在鎖裏進行發送。
    • 接收數據時,A、B 雙方就用各自的鑰匙來解鎖。其餘人沒有鑰匙,也就獲取不到數據。
    • 實現了雙向通訊加密。

互聯網通訊是雙向的,因此咱們須要使用對稱加密,但是,怎樣才能保證通訊雙方都有一把相同的鑰匙呢?

目前的解決方案:

  • 先使用非對稱加密,進行祕鑰協商,讓通訊雙方拿到相同的鑰匙。
  • 而後使用對稱加密,進行加密傳輸。

祕鑰協商過程如圖:

圖中劃重點:

  1. 客戶端發送自身支持的加密算法。
  2. 服務器端選擇一種加密算法,同時返回數字證書。
  3. 客戶端確認證書有效。
  4. 客戶端生成隨機數,並使用證書中的服務器公鑰加密,而後發送給服務器。
  5. 服務器端使用私鑰解密,得到隨機數。
  6. 雙方使用第 2 步肯定的加密算法,把隨機數進行加密,便可得到相同的對稱加密祕鑰。

Ok,祕鑰協商以後,咱們的 SSL 安全層也就建好了。

祕鑰協商時存在一個問題:

祕鑰協商時,怎麼保證是和真正的服務器在協商,而不是一箇中間人呢?

答:數字證書

數字證書重點關注 2 個部分:

  • 服務器公鑰
  • 數字簽名

其中,數字簽名又是由服務器公鑰和證書私鑰加密生成的,目的是爲了防止服務器公鑰被篡改。

有了數字證書,客戶端就能經過驗證證書,來判斷服務器是不是真正的服務器了。

驗證邏輯以下:

能夠看到,數字證書經過一樣的算法進行解密,若是獲得相同的信息摘要,就能保證數據是有效的,若是不一致,則會驗證失敗,拒絕後續的請求。

到這裏爲止,全部的準備工做都就緒了,接下來纔是發送 HTTP 請求。

發送 HTTP 請求

HTTP 協議其實就是制定了一個通訊規則,規定了客戶端和服務器之間的通訊格式。

以請求 baidu 首頁爲例:

如上圖所示,發起 HTTP 請求時,必須遵照如下規則:

  • 請求方法(必填) GET
  • 請求地址(必填) /
  • HTTP 協議版本(必填) 1.1
  • 其餘 HTTP 頭部字段(可選) HostUser-AgentAccept
  • 請求參數,放在空行後面(可選)

服務器響應請求時,一樣遵照了 HTTP 響應規則:

  • HTTP 協議版本(必填) 1.1
  • 響應狀態碼(必填) 200
  • 狀態碼描述(必填) OK
  • 其餘 HTTP 頭部字段(可選) DateServerETagLast-Modified
  • 請求參數,放在空行後面(可選)

只要咱們遵照這個規則,就能進行 HTTP 通訊了。

到目前爲止,咱們已經分析完成了數據請求的全部過程,你是否都理解了呢?

思考與總結

本文經過一個網絡請求,對整個 HTTP、TCP、IP、以太網等協議進行了流程化分析,最後再梳理一下:

  1. 請求 baidu.com。
  2. DNS 解析 baidu.com,獲得 IP 地址。
  3. 創建 TCP 鏈接。
  4. IP 協議經過算法,計算出一條通往服務器最優路徑。
  5. IP 沿着路徑跳轉時,會經過 ARP 協議把 IP 地址轉換成 Mac 地址。
  6. 以太網經過 Mac 地址,找到通訊雙方的硬件接口。
  7. 物理層經過網線做爲載體,在兩個硬件接口之間傳輸比特信號。
  8. TCP 鏈接創建完畢。
  9. 創建 SSL 安全層。
  10. 發送 HTTP 請求。

最後,若是你對此有任何想法,歡迎留言評論!

相關文章
相關標籤/搜索