以下為個人總結,圖源大部分會來自網絡和JavaGuide
網絡分層模型
OSI七層模型
各層的常見協議
- 應用層 用戶接口 HTTP, FTP, SMTP, DNS
- 表示層 數據格式轉換 SSL/TLS, JSON, JPEG
- 會話層 會話管理 NetBIOS, RPC, SSH
- 傳輸層 端到端通信 TCP, UDP, QUIC
- 網絡層 路由尋址 IP, ICMP, OSPF, BGP
- 數據鏈路層 幀傳輸 Ethernet, Wi-Fi, ARP
- 物理層 比特流傳輸 Ethernet, USB, 光纖
層間通信
發送方(封裝):
應用層 → 表示層 → 會話層 → 傳輸層 → 網絡層 → 數據鏈路層 → 物理層
Message → 加密 → 會話ID → TCP頭 → IP頭 → 幀頭/尾 → 比特流
接收方(解封裝):
物理層 → 數據鏈路層 → 網絡層 → 傳輸層 → 會話層 → 表示層 → 應用層
比特流 → 幀解析 → 路由檢查 → 端口分配 → 會話恢復 → 解密 → 用戶數據
TCP/IP四層模型
- 應用層 直接為用戶應用提供服務。HTTP、FTP、DNS、SMTP、SSH。
- 傳輸層 提供端到端的可靠或不可靠數據傳輸。TCP、UDP。
- 網絡層 實現主機到主機的邏輯尋址和路由。封裝數據為IP數據報,包含源/目的IP地址。IP、ICMP、IGMP。
- 網絡接口層 負責在物理網絡中傳輸數據幀。 以太網、Wi-Fi、ARP。
層間通信
發送端:
應用層 → 傳輸層 → 網絡層 → 網絡接口層
應用層數據 → [TCP頭]+數據 → [IP頭]+TCP段 → [幀頭]+IP包+[幀尾] → 網絡傳輸
接收端:
網絡接口層 → 網絡層 →傳輸層 → 應用層
網絡傳輸 → 移除幀頭/尾 → 移除IP頭 → 移除TCP頭 → 應用層數據
TCP相關
TCP的三次握手
- 第一次握手(SYN)
客戶端發送 SYN=1(同步標志位),并隨機生成一個初始序列號 seq=x。
目的:向服務器發起連接請求,并告知自己的初始序列號。
此時客戶端進入 SYN_SENT 狀態。 - 第二次握手(SYN+ACK)
服務器收到 SYN 后,回復 SYN=1 和 ACK=1(確認標志位),同時生成自己的初始序列號 seq=y,并確認客戶端的序列號 ack=x+1。
目的:確認客戶端的 SYN,并告知自己的初始序列號。
此時服務器進入 SYN_RCVD 狀態。 - 第三次握手(ACK)
客戶端收到 SYN+ACK 后,發送 ACK=1,確認服務器的序列號 ack=y+1,并攜帶自己的序列號 seq=x+1(因為第一次握手的 SYN 占用一個序號)。
目的:確認服務器的 SYN,完成雙向連接建立。
此時雙方進入 ESTABLISHED 狀態,可以開始數據傳輸。
為什么需要三次握手?
- 確認雙方的收發能力
第一次握手:服務器確認客戶端能發。
第二次握手:客戶端確認服務器能收和發。
第三次握手:服務器確認客戶端能收。 - 防止歷史重復連接初始化導致的資源浪費
如果是兩次握手,服務器可能因收到延遲的舊 SYN 請求而誤建連接,而客戶端實際不需要。 - 同步初始序列號(ISN)
雙方通過三次握手交換初始序列號,確保數據按序傳輸。
兩次握手可以嗎?
不行,服務器無法確認客戶端是否收到自己的 SYN+ACK,可能導致半連接(服務器已就緒,客戶端未就緒)。
四次握手可以嗎?
如果改成四次握手(例如:客戶端再發一個 ACK 確認服務器的 ACK),實際上是冗余的,因為第三次握手已經能確保雙方通信正常,額外的確認不會帶來更多好處,只會增加延遲。
四次揮手
- 第一次揮手(FIN)
客戶端發送 FIN=1(終止標志位)和序列號 seq=u,表示客戶端沒有數據要發送了,請求關閉連接。
客戶端狀態:FIN_WAIT_1(等待服務器的 ACK)。
注意:此時客戶端仍可以接收數據(因為 TCP 是全雙工的)。 - 第二次揮手(ACK)
服務器收到 FIN 后,回復 ACK=1 和確認號 ack=u+1,表示已收到客戶端的關閉請求。
服務器狀態:CLOSE_WAIT(等待服務器應用層處理完剩余數據)。
客戶端狀態:收到 ACK 后進入 FIN_WAIT_2(等待服務器的 FIN)。 - 第三次揮手(FIN)
服務器處理完剩余數據后,發送 FIN=1 和 seq=v(可能是新的序列號),表示服務器也沒有數據要發送了,請求關閉連接。
服務器狀態:LAST_ACK(等待客戶端的最終 ACK)。 - 第四次揮手(ACK)
客戶端收到 FIN 后,發送 ACK=1 和 ack=v+1,表示確認服務器的關閉請求。
客戶端狀態:進入 TIME_WAIT(等待 2MSL 后徹底關閉)。
服務器狀態:收到 ACK 后立即關閉連接。
為什么需要四次揮手?
- TCP 是全雙工的,雙方可以獨立關閉連接:
- 客戶端主動關閉(第一次揮手)→ 服務器確認(第二次揮手).
- 服務器可能還有數據要發送,不能立即關閉。
- 服務器處理完數據后主動關閉(第三次揮手)→ 客戶端確認(第四次揮手)。
如果改成三次揮手?
- 服務器沒有需要發送的消息時,可能會退化為三次揮手。
- 但是如果將所有的四次揮手改為三次揮手會導致:
- 服務器無法在確認客戶端 FIN 后繼續發送剩余數據。
- 可能造成數據丟失或不完整關閉。
為什么客戶端需要 TIME_WAIT 狀態?
- 等待 2MSL(Maximum Segment Lifetime,報文最大生存時間),確保:
- 服務器收到最后的 ACK(如果丟失,服務器會重傳 FIN)。
- 讓網絡中殘留的舊 TCP 報文失效,避免影響新連接。
- 默認 2MSL 時間:Linux 通常為 60 秒,Windows 為 4 分鐘。
為什么服務器需要 CLOSE_WAIT 狀態?
- 允許服務器處理剩余數據
當客戶端發送 FIN 請求關閉連接時,服務器可能仍有數據需要發送(如未傳完的文件、數據庫查詢結果等)。
CLOSE_WAIT 狀態讓服務器有機會繼續發送剩余數據,而不是立即關閉連接。 - 確保應用程序正確釋放資源
服務器需要等待應用程序(如 HTTP 服務器、數據庫服務)處理完所有邏輯后,主動調用 close() 或 shutdown() 來發送自己的 FIN。
如果直接跳過 CLOSE_WAIT,可能導致:數據丟失(如未發送完的響應)和資源泄漏(如未關閉的文件句柄、數據庫連接)。
CLOSE_WAIT 可能引發的問題
連接泄漏(大量 CLOSE_WAIT 堆積)
原因:服務器應用程序未正確調用 close(),導致 CLOSE_WAIT 狀態長期存在。
后果:占用系統資源(文件描述符、內存)。最終導致服務器無法接受新連接(Too many open files)。
TCP的擁塞控制
慢啟動、擁塞避免、快重傳、快恢復
- 慢啟動(Slow Start)
目的:初始階段快速探測可用帶寬。
規則:初始擁塞窗口(cwnd)通常為 1 MSS(Maximum Segment Size)。每收到一個 ACK,cwnd 指數增長(cwnd *= 2)。直到 cwnd 達到慢啟動閾值(ssthresh)或發生丟包。 - 擁塞避免(Congestion Avoidance)
目的:接近網絡容量時轉為線性增長,避免激進引發擁塞。
規則:當 cwnd >= ssthresh 時,每 RTT(往返時間)cwnd += 1 MSS。增長速率從指數變為線性。 - 快速重傳(Fast Retransmit)
目的:避免等待超時,快速恢復丟失的包。
規則:如果發送方收到 3 個重復 ACK(DupACK),立即重傳丟失的包。無需等待超時計時器(RTO)到期。 - 快速恢復(Fast Recovery)
目的:在快速重傳后避免重置 cwnd,保持較高吞吐量。
規則:發生快速重傳后,ssthresh = cwnd / 2,cwnd = ssthresh + 3 MSS。每收到一個 DupACK,cwnd += 1 MSS(允許發送新數據)。收到新數據的 ACK 后,退出快速恢復,進入擁塞避免階段。
TCP和UDP的區別
- TCP:面向連接,需三次握手建立可靠通道。確保數據可靠傳輸(確認、重傳、排序)。通過滑動窗口和擁塞算法(如慢啟動)優化傳輸。頭部較大(至少20字節),延遲較高。字節流模式,無固定邊界。
- UDP:無連接,直接發送數據包。不保證可靠性,可能丟包或亂序。無控制機制,全速發送。頭部僅8字節,開銷小,延遲低。:保留數據報邊界,接收與發送一致。
TCP的粘包和拆包
-
粘包 (Packet Sticking)
定義:發送方發送的多個數據包被接收方當作一個數據包接收 -
拆包 (Packet Splitting)
定義:發送方發送的一個數據包被接收方拆分成多個數據包接收
產生原因
-
共同原因
- TCP是面向流的協議:沒有消息邊界概念,數據被視為字節流
- 滑動窗口機制:為提高效率可能合并或拆分數據包
-
粘包特定原因
- Nagle算法:合并小包減少網絡傳輸次數
- 發送方快速連續發送小包:內核緩沖區可能合并
-
拆包特定原因
- 數據包大于MSS(最大報文段長度):TCP必須拆分
- 數據包大于接收緩沖區:應用層讀取時可能分多次
- 網絡設備限制:某些網絡設備對包大小有限制
解決方案
- 消息定長法:每個消息固定長度,不足補位
- 分隔符法:使用特殊字符作為消息邊界
- 長度前綴法:在消息前添加長度字段,通常使用固定字節表示長度(如4字節)
HTTP相關
HTTP/1.0
- 特點
短連接:每個請求/響應后關閉 TCP 連接(高延遲)。
無狀態:每次請求需攜帶完整頭部(無 Host 字段,無法支持虛擬主機)。 - 基礎功能:支持 GET、POST、HEAD 方法。
- 缺點
性能差:頻繁建立 TCP 連接,高延遲。
無 Host 頭:無法區分同一 IP 的不同域名。
HTTP/1.1
- 改進
持久連接(Keep-Alive):默認復用 TCP 連接,減少握手開銷。
管道化(Pipelining):允許連續發送多個請求(但響應必須按序返回,易阻塞)。
Host 頭:支持虛擬主機(一個 IP 托管多個網站)。
分塊傳輸(Chunked Encoding):支持流式傳輸大文件。
緩存控制:新增 Cache-Control、ETag 等頭部。 - 缺點
隊頭阻塞(Head-of-Line Blocking):同一連接中,前一個請求未完成會阻塞后續請求。
頭部冗余:每次請求攜帶重復頭部(如 Cookie、User-Agent)。
HTTP/2
- 改進
二進制協議:替代文本格式,解析更高效。
多路復用(Multiplexing):單個連接并行傳輸多個請求/響應,解決隊頭阻塞。
頭部壓縮(HPACK):減少冗余頭部大小。
服務器推送(Server Push):服務器可主動推送資源(如 CSS/JS)。
流優先級:允許設置請求優先級。 - 缺點
仍依賴 TCP:TCP 層的隊頭阻塞問題未解決(如丟包導致所有流等待重傳)。
握手延遲:TLS 非強制(但主流瀏覽器要求 HTTPS)。
HTTP/3
- 改進
基于 QUIC 協議:運行在 UDP 上,替代 TCP。
0-RTT 握手:減少連接建立時間。
內置加密:默認使用 TLS 1.3。
解決 TCP 隊頭阻塞:每個流獨立傳輸,丟包不影響其他流。
改進的多路復用:更高效的資源并行加載。 - 缺點
部署復雜:需要服務器和客戶端支持 QUIC(如 Cloudflare、Nginx 已支持)。
UDP 被某些網絡限制:可能被防火墻攔截。
HTTPS(HTTP + TLS/SSL)
- 特點
加密傳輸:使用 TLS/SSL 加密數據,防止竊聽和篡改。
身份驗證:通過證書驗證服務器身份。
混合加密:非對稱加密(握手) + 對稱加密(數據傳輸)。 - 與 HTTP 的關系
可搭配任何 HTTP 版本(如 HTTPS/1.1、HTTPS/2)。
HTTP/3 默認加密(QUIC 內置 TLS 1.3)。
HTTPS 連接建立流程
- TCP 三次握手
客戶端與服務器建立 TCP 連接(SYN → SYN-ACK → ACK)。 - TLS 握手
- Client Hello:客戶端發送支持的加密算法列表和隨機數(Client Random)。
- Server Hello:服務器選擇加密算法,返回隨機數(Server Random)和數字證書(含公鑰)。
- 驗證證書:客戶端用 CA 公鑰驗證證書真實性。
- 密鑰交換:
- 客戶端生成 Pre-Master Key,用服務器公鑰加密后發送。
- 雙方通過 Client Random + Server Random + Pre-Master Key 生成會話密鑰(對稱加密密鑰)。
- 加密通信
使用會話密鑰加密傳輸 HTTP 數據,防止竊聽和篡改。