天天看點

輸入網址按回車,到底發生了什麼

轉載自:腳本之家

僅用于自我學習,侵權删!

詳解輸入網址點選回車,背景到底發生了什麼。透析 HTTP 協定與 TCP 連接配接之間的千絲萬縷的關系。掌握為何是三次握手四次揮手?time_wait 存在的意義是什麼?全面圖解重點問題,再也不用擔心面試被問到。

大緻流程:

  • URL解析
  • DNS查詢
  • TCP連接配接
  • 伺服器處理請求
  • 用戶端接收HTTP封包響應
  • 渲染頁面

重點來了:

  • 如何了解 TCP 的三次握手和四次揮手?每次握手用戶端與服務端是怎樣的狀态?
  • 為何揮手會出現 2MSL ,遇到大量的 Socket 處在 TIME_WAIT 或者 CLOSE_WAIT 狀态是什麼問題?
  • 三次握手與四次揮手的過程是怎樣的?
  • HTTP的封包格式又是怎樣的?

URL解析

位址解析:首先判斷你輸入的是一個合法的 URL 還是一個待搜尋的關鍵詞,并且根據你輸入的内容進行自動完成、字元編碼等操作。

HSTS 由于安全隐患,會使用 HSTS 強制用戶端使用 HTTPS 通路頁面。

其他操作浏覽器還會進行一些額外的操作,比如安全檢查、通路限制(之前國産浏覽器限制 996.icu)。

輸入網址按輸入,到底發生了什麼

DNS查詢

輸入網址按輸入,到底發生了什麼
  1. 浏覽器緩存:先查詢是否在緩存中,沒有則調用系統庫函數進行查詢。
  2. 作業系統緩存:作業系統也有自己的 DNS 緩存,但在這之前,會先檢查域名是否存在本地的 Hosts 檔案裡,沒有則向 DNS 伺服器發送查詢請求。
  3. 路由器緩存。
  4. ISP DNS 緩存: ISP DNS 就是在用戶端電腦上設定的首選 DNS 伺服器,它們在大多數情況下都會有緩存。

根域名伺服器查詢

在前面所有步驟沒有緩存的情況下,本地 DNS 伺服器會将請求轉發到網際網路上的根域,下面這個圖很好的诠釋了整個流程:

輸入網址按輸入,到底發生了什麼

需要注意的是:

  1. 遞歸方式:一路查下去中間不傳回,得到最終結果才傳回資訊(浏覽器到本地 DNS 伺服器的過程)
  2. 疊代方式,就是本地 DNS 伺服器到根域名伺服器查詢的方式
  3. 什麼是 DNS 劫持
  4. 前端 dns-prefetch 優化

TCP 連接配接建立與斷開

TCP/IP 分為四層,在發送資料時,每層都要對資料進行封裝:

輸入網址按輸入,到底發生了什麼

應用層:發送 HTTP 請求

浏覽器從位址欄得到伺服器 IP ,接着構造一個 HTTP 封包,其中包括:

  • 請求報頭(Request Header):請求方法、目标位址、遵循的協定等
  • 請求主體,請求參數、比如 body 裡面的參數

傳輸層:TCP 傳輸封包

傳輸層會發起一條到伺服器的 TCP 連接配接,為了友善傳輸,會對資料進行分割(以封包段位機關),并标記編号,友善伺服器接受時能夠準确地還原封包資訊。在建立連接配接前,會先進行 TCP 三次握手。

網絡層:IP 協定查詢 MAC 位址

将資料段打包,并加入源及項目的 IP 位址,并且負責尋找傳輸路線。判斷目标位址是否與目前位址處于同一網絡中,是的話直接根據 MAC 位址發送,否則使用路由表查找下一個位址,以及使用 ARP 協定查詢它的 MAC 位址。

鍊路層:以太網協定

根據以太網協定将資料分為以“幀”為機關的資料包,每一幀分為兩個部分:

  • 标頭:資料包的發送者、接受者、資料類型
  • 資料:資料包具體内容

MAC位址

以太網規定了連入網絡的所有裝置都必須具備“網卡”接口,資料包都是從一塊網卡傳遞到另一塊網卡,網卡的位址就是 Mac 位址。每一個 Mac 位址都是獨一無二的,具備了一對一的能力。

主要的請求過程:

  1. 浏覽器從位址欄中擷取伺服器的 IP 和端口号;
  2. 浏覽器與伺服器之間通過 TCP 三次握手建立連接配接;
  3. 浏覽器向伺服器發送封包;
  4. 伺服器接收封包處理,同時将響應封包發給浏覽器;
  5. 浏覽器解析封包,渲染輸出到頁面;

三次握手

在傳輸層傳輸資料之前需要建立連接配接,也就是三次握手建立可靠連接配接。

輸入網址按輸入,到底發生了什麼

首先建立連接配接前需要 Server 端先監聽端口,是以 Server 端建立連接配接前的初始狀态就是 LISTEN 狀态,這時 Client 端準備建立連接配接,先發送一個 SYN 同步包,發送完同步包後, Client 端的連接配接狀态變成了 SYN_SENT 狀态。Server 端收到了 SYN 後,同意建立連接配接,會向 Client 端恢複一個 ACK。

由于 TCP 是雙工傳輸,Server 端也會同時向 Client 端發送了一個 SYN ,申請 Server 向 Client 方向建立連結。發送完 ACK 和SYN 後,Server 端的連結狀态就變成了 SYN_RCVD。

Client 收到 Server 的 ACK 後,Client 端的連結狀态就變成了 ESTABLISHED 狀态,同時, Client 向 Server 端發送 ACK,回複 Server 端的 SYN 請求。

Server 端收到 Client 端的 ACK 後,Server 端的連結狀态也就變成了 ESTABLISHED 狀态,此時建連完成,雙方随時可以進行資料傳輸。

在面試時需要明白三次握手是為了建立雙向的連結,需要記住 Client 端和 Server 端的連結狀态變化。另外回答建連的問題時,可以提到 SYN 洪水攻擊發生的原因,就是 Server 端收到 Client 端的 SYN 請求後,發送了 ACK 和 SYN,但是 Client 端不進行回複,導緻 Server 端大量的連結處在 SYN_RCVD 狀态,進而影響其他正常請求的建連。可以設定 tcp_synack_retries = 0 加速半連結的回收速度,或者調大 tcp_max_syn_backlog 來應對少量的 SYN 洪水攻擊。

四次揮手

我們隻要關注 80 端口與 13743 端口建立的連接配接斷開過程,浏覽器通過 13747 端口發送 [ FIN,ACK ] 這裡是不是跟很多網上看到的不一樣?

  1. 其實是用戶端在發送 [ FIN ] 封包的時候順帶發了一個 [ ACK ] 确認上次傳輸确認。
  2. 接着服務端通過 80 端口響應了 [ ACK ] ,然後立馬響應 [ FIN , ACK ] 表示資料傳輸完了,可以關閉連接配接。
  3. 最後浏覽器通過 13743 端口發送 [ ACK ] 包給服務端,用戶端與服務端連接配接就關閉了。

具體流程如下圖抓包所示:

輸入網址按輸入,到底發生了什麼

三次揮手與四次揮手

輸入網址按輸入,到底發生了什麼

用戶端:

  • SYN_SENT - 用戶端發起第 1 次握手後,連結狀态為 SYN_SENT ,等待服務端核心進行應答,如果服務端來不及處理(例如服務端的 backlog 隊列已滿)就可以看到這種狀态的連結。
  • ESTABLISHED - 表示連結處于正常狀态,可以進行資料傳送。用戶端收到伺服器回複的 SYN + ACK 後,對服務端的 SYN 單獨回複(第 3 次握手),連接配接建立完成,進入 ESTABLISHED 狀态。服務端程式收到第 3 次握手包後,也進入 ESTABLISHED 狀态。
  • FIN_WAIT_1 - 用戶端發送了關閉連接配接的 FIN 封包後,等待服務端回複 ACK 确認。
  • FIN_WAIT_2 - 表示我方已關閉連接配接,正在等待服務端關閉。用戶端發了關閉連接配接的 FIN 封包後,伺服器發回 ACK 應答,但是沒進行關閉,就會處于這種狀态。
  • TIME_WAIT - 雙方都正常關閉連接配接後,用戶端會維持 TIME_WAIT 一段時間,以確定最後一個 ACK 能成功發送到服務端。停留時長為 2 倍的 MAL (封包最大生存時間),Linux 下大約是 60 秒。是以在一個頻繁建立短連接配接的伺服器上通常可以看到成千上萬的 TIME_WAIT 連接配接。