摘要:輸入網址并點回車,后臺到底發生了什么,透析 HTTP 協議與 TCP 連接之間的千絲萬縷的關系,掌握為何是三次握手四次揮手?time_wait 存在的意義是什么?全面圖解重點問題,再也不用擔心面試問這個問題,
本文分享自華為云社區《輸入網址,小手一點,后面到底發生了什么?》,作者:龍哥手記,
輸入網址并點回車,后臺到底發生了什么,透析 HTTP 協議與 TCP 連接之間的千絲萬縷的關系,掌握為何是三次握手四次揮手?time_wait 存在的意義是什么?全面圖解重點問題,再也不用擔心面試問這個問題,
大致流程
- URL 決議,決議 http 協議、埠、資源地址,
- DNS 查詢:首先查詢本地 host,再訪問 DNS 服務器將 域名決議成 ip 地址,
- 建立 TCP 連接,
- 服務器收到請求后處理,并且構造回應回傳給客戶端,
- 客戶端接收 HTTP 報文回應,
- 渲染頁面,最后有可能會四次揮手斷開連接,也可能不會而是復用連接,
重點來了:
- 如何理解 TCP 的三次握手與四次揮手?每次握手客戶端與服務端是怎樣的狀態?
- 為何揮手會出現 2MSL,遇到大量 Socket 處在 TIME_WAIT 或者 CLOSE_WAIT 狀態是什么問題?
- 三次握手與四次揮手的程序是怎樣的?
- HTTP 的報文格式又是怎樣的?
URL 決議
url 遵守的規則是這個樣子
scheme://host.domain:port/path/filename
每個名詞的含義如下解釋:
- scheme 定義應用層協議型別,比如 http、https、 ftp 等;
- host 定義域主機(http 的默認主機是 www);
- domain 定義因特網域名,比如 segmentfault.com;
- port 主機的埠,http 默認是 80, https 默認是 443;
- path 服務器上的資源路徑;
- filename - 定義檔案/資源的名稱;
DNS 查詢
瀏覽器不能直接通過域名找到服務器,只能通過 IP 地址,
那瀏覽器是如何通過域名查詢到我們輸入的 url 對應的 IP 呢?
- 瀏覽器快取:按照一定頻率快取 DNS 資料,
- 作業系統快取:如果瀏覽器快取找不到記錄則去作業系統中找,
- 路由快取:路由器 DNS 快取,
- ISP 的 DNS 服務器:ISP 是互聯網服務提供商(Internet Service Provider)的簡稱,ISP 有專門的 DNS 服務器應對 DNS 查詢請求,
- 根服務器:ISP 的 DNS 服務器還找不到的話,它就會向根服務器發出請求,進行遞回查詢(DNS 服務器先問根域名服務器.com 域名服務器的 IP 地址,然后再問 .baidu 域名服務器,依次類推)
TCP 連接建立與斷開
通過域名決議出 IP 地址以后就要建立 TCP/IP 連接了,
TCP/IP 分為四層,每一層都會加上一個頭部再發送給下一層,到了接收方后,對應的每一層則把對應層的頭部決議拆除,丟上上一層,跟發送端的程序反過來,
TCP/IP四層模型
應用層:發送 HTTP 請求
瀏覽器從地址欄得到服務器 IP,接著構造一個 HTTP 報文,其中包括:
- 請求行包含請求方法、URL、協議版本
- 請求報頭(Request Header):由 “關鍵字: 值”對組成,每行一對,關鍵字與值使用英文 “:” 分割
- 請求體:請求引數,并不是所有的請求都有請求引數,一般 get 引數 的格式 name=tom&password=1234&realName=tomson,也可以將引數放在 body 里面,
傳輸層:TCP 傳輸報文
在傳輸報文之前會先建立 TCP/IP 連接,也就是后面我們要說的三次握手,
在這一層解決了資料可靠傳輸、及流量控制、擁塞控制,
可靠傳輸
對于發送方發送的資料,接收方在接受到資料之后必須要給予確認,確認它收到了資料,如果在規定時間內,沒有給予確認則意味著接收方沒有接受到資料,然后發送方對資料進行重發,
TCP的可靠傳輸是通過確認和超時重傳的機制來實作的,而確認和超時重傳的具體的實作是通過以位元組為單位的滑動視窗機制來完成,
TCP擁塞控制
TCP協議通過慢啟動機制、擁塞避免機制、加速遞級訓制、快重傳和快恢復機制來共同實作擁塞控制,
流量控制
采用通知視窗實作對發送端的流量控制,通知視窗大小的單位是位元組,TCP通過在TCP資料段首部的視窗欄位中填入當前設定的接收視窗(即通知視窗)的大小,用來告知對方 '我方當前的接收視窗大小',以實作流量控制,
通信雙方的發送視窗大小由雙方在連接建立的時候商定,在通信程序,雙方可以動態地根據自己的情況調整對方的發送視窗大小,
網路層:IP 協議查詢 MAC 地址
將資料段打包,并加入源及目標的 IP 地址,并且負責尋找傳輸路線,判斷目標地址是否與當前地址處于同一網路中,是的話直接根據 Mac 地址發送,否則使用路由表查找下一跳地址,以及使用 ARP 協議查詢它的 Mac 地址,
鏈路層:以太網協議
根據以太網協議將資料分為以“幀”為單位的資料包,每一幀分為兩個部分:
- 標頭:資料包的發送者、接受者、資料型別
- 資料:資料包具體內容
Mac 地址
以太網規定了連入網路的所有設備都必須具備“網卡”介面,資料包都是從一塊網卡傳遞到另一塊網卡,網卡的地址就是 Mac 地址,每一個 Mac 地址都是獨一無二的,具備了一對一的能力,
三次握手
在傳輸層傳輸資料之前需要建立連接,也就是三次握手創建可靠連接,
三次握手
首先建立鏈接前需要 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] 這里是不是跟很多網上看到的不一樣?
- 其實是客戶端在發送 [FIN] 報文的時候順帶發了一個 [ACK] 確認上次傳輸確認,
- 接著服務端通過 80 埠回應了 [ACK] ,然后立馬回應 [FIN, ACK] 表示資料傳輸完了,可以關閉連接,
- 最后瀏覽器通過 13743 埠 發送 [ACK] 包給服務端,客服端與服務端連接就關閉了,
具體流程如下圖抓包所示:
三次握手與四次揮手
TCP 連接與斷開
客戶端:
- 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 倍的 MSL (報文最大生存時間),Linux 下大約是 60 秒,所以在一個頻繁建立短連接的服務器上通常可以看到成千上萬的 TIME_WAIT 連接,
服務端:
- LISTEN - 表示當前程式正在監聽某個埠時,
- SYN_RCVD - 服務端收到第 1 次握手后,進入 SYN_RCVD 狀態,并回復一個 SYN+ACK(第 2 次握手),再等待對方確認,
- ESTABLISHED - 表示連接處于正常狀態,可以進行資料傳送,完成 TCP3 次握手后,連接建立完成,進入 ESTABLISHED 狀態,
- CLOSE_WAIT - 表示客戶端已經關閉連接,但是本地還沒關閉,正在等待本地關閉,有時客戶端程式已經退出了,但服務端程式由于例外或 BUG 沒有呼叫 close()函式對連接進行關閉,那在服務器這個連接就會一直處于 CLOSE_WAIT 狀態,而在客戶機已經不存在這個連接了,
- LAST_ACK - 表示正在等待客戶端對服務端的關閉請求進行最終確認,
TIME_WAIT 狀態存在的理由:
劃重點了
- 可靠地實作 TCP 全雙工連接的終止 在進行關閉連接四路握手協議時,最后的 ACK 是由主動關閉端發出的,如果這個最終的 ACK 丟失,服務器將重發最終的 FIN,因此客戶端必須維護狀態資訊允 許它重發最終的 ACK,如 果不維持這個狀態資訊,那么客戶端將回應 RST 分節,服務器將此分節解釋成一個錯誤( 在 java 中會拋出 connection reset 的 SocketException),因而,要實作 TCP 全雙工連接的正常終 止,必須處理終止序列四個分節中任何一個分節的丟失情況,主動關閉 的客戶端必須維持狀 態資訊進入 TIME_WAIT 狀態,
- 允許老的重復分節在網路中消逝 TCP 分節可能由于路由器例外而“迷途”,在迷途期間,TCP 發送端可能因確認超時而重發這個 分節,迷途的分節在路由器修復后也會被送到最終目的地,這個 原來的迷途分節就稱為 lost duplicate,在關閉一個 TCP 連接后,馬上又重新建立起一個相同的 IP 地址和埠之間的 TCP 連接,后一個連接被稱為前一個連接的化身 ( incarnation),那么有可能出現這種情況,前一 個連接的迷途重復分組在前一個連接終止后出現,從而被誤解成從屬于新的化身,為了避免 這個情 況,TCP 不允許處于 TIME_WAIT 狀態的連接啟動一個新的化身,因為 TIME_WAIT 狀 態持續 2MSL,就可以保證當成功建立一個 TCP 連接的時 候,來自連接先前化身的重復分組已 經在網路中消逝,
另外回答斷鏈的問題時,可以提到實際應用中有可能遇到大量 Socket 處在 TIME_WAIT 或者 CLOSE_WAIT 狀態的問題,一般開啟 tcp_tw_reuse 和 tcp_tw_recycle 能夠加快 TIME-WAIT 的 Sockets 回收;而大量 CLOSE_WAIT 可能是被動關閉的一方存在代碼 bug,沒有正確關閉鏈接導致的,
簡單地說就是
- 保證 TCP 協議的全雙工連接能夠可靠關閉;
- 保證這次連接的重復資料段從網路中消失,防止埠被重用時可能產生資料混淆;
點擊關注,第一時間了解華為云新鮮技術~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/541875.html
標籤:Html/Css
上一篇:權限控制在數堆疊產品的實踐
