91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

TCP三次握手與四次揮手的詳細(xì)過程

馬哥Linux運(yùn)維 ? 來源:馬哥Linux運(yùn)維 ? 2026-02-25 10:38 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

一、概述

1.1 背景介紹

TCP 三次握手和四次揮手,大概是網(wǎng)絡(luò)領(lǐng)域被問爛了的面試題。但真正能把狀態(tài)變遷、序列號(hào)變化、抓包細(xì)節(jié)講清楚的人并不多。很多人背了八股文,一到生產(chǎn)環(huán)境看 Wireshark 抓包就懵了——SYN_RECV 隊(duì)列溢出怎么排查?TIME_WAIT 堆積幾萬(wàn)個(gè)怎么處理?RST 到底是誰(shuí)發(fā)的?這些問題光靠背書解決不了。

這篇文章從 TCP 報(bào)文格式講起,逐字節(jié)拆解三次握手和四次揮手的完整過程,配合 Wireshark 和 tcpdump 的實(shí)際抓包輸出,把每個(gè)狀態(tài)變遷都對(duì)應(yīng)到真實(shí)的網(wǎng)絡(luò)包上。同時(shí)覆蓋 TCP 重傳機(jī)制、擁塞控制算法對(duì)比(BBR vs Cubic),以及生產(chǎn)環(huán)境中最常見的 TCP 問題排查和內(nèi)核參數(shù)調(diào)優(yōu)。

1.2 技術(shù)特點(diǎn)

報(bào)文級(jí)拆解:從 TCP Header 的每個(gè)字段出發(fā),理解握手揮手的本質(zhì)而非死記硬背

抓包驅(qū)動(dòng):所有理論都配合 Wireshark/tcpdump 的真實(shí)抓包輸出驗(yàn)證

狀態(tài)機(jī)完整:覆蓋 TCP 全部 11 種狀態(tài)及其轉(zhuǎn)換條件

生產(chǎn)導(dǎo)向:重點(diǎn)放在 TIME_WAIT 優(yōu)化、半連接隊(duì)列溢出、RST 排查等實(shí)際問題

1.3 適用場(chǎng)景

場(chǎng)景一:面試準(zhǔn)備,需要深入理解 TCP 連接管理機(jī)制而非停留在八股文層面

場(chǎng)景二:生產(chǎn)環(huán)境 TCP 連接異常排查,需要通過抓包定位具體問題

場(chǎng)景三:高并發(fā)服務(wù)的內(nèi)核網(wǎng)絡(luò)參數(shù)調(diào)優(yōu),解決 TIME_WAIT 堆積、SYN Flood 等問題

場(chǎng)景四:微服務(wù)架構(gòu)下的連接管理優(yōu)化,理解連接復(fù)用和優(yōu)雅關(guān)閉

1.4 環(huán)境要求

組件 版本要求 說明
操作系統(tǒng) Ubuntu 24.04 LTS / RHEL 9.x 內(nèi)核 6.8+,BBR v3 支持
Wireshark 4.4+ GUI 抓包分析工具
tcpdump 4.99+ 命令行抓包工具
ss / iproute2 6.x+ 替代 netstat 的連接狀態(tài)查看工具
curl 8.x+ HTTP 請(qǐng)求測(cè)試

二、TCP 報(bào)文格式

在聊握手揮手之前,先把 TCP 報(bào)文頭的結(jié)構(gòu)搞清楚。不理解報(bào)文格式,后面看抓包就是看天書。

2.1 TCP Header 結(jié)構(gòu)

TCP 報(bào)文頭最小 20 字節(jié),最大 60 字節(jié)(含 Options)。結(jié)構(gòu)如下:

0          1          2          3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Source Port     |    Destination Port    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Sequence Number            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Acknowledgment Number           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data |    |C|E|U|A|P|R|S|F|                |
| Offset| Rsrvd |W|C|R|C|S|S|Y|I|      Window       |
|    |    |R|E|G|K|H|T|N|N|                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Checksum      |     Urgent Pointer    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Options (variable)             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.2 關(guān)鍵字段解析

重點(diǎn)關(guān)注幾個(gè)和握手揮手直接相關(guān)的字段:

序列號(hào)(Sequence Number,32 位):標(biāo)識(shí)從 TCP 發(fā)送端向接收端發(fā)送的數(shù)據(jù)字節(jié)流中的第一個(gè)字節(jié)的編號(hào)。握手階段的初始序列號(hào)(ISN)是隨機(jī)生成的,不是從 0 開始,這是為了防止歷史連接的殘留包干擾新連接。

確認(rèn)號(hào)(Acknowledgment Number,32 位):期望收到對(duì)方下一個(gè)報(bào)文段的第一個(gè)數(shù)據(jù)字節(jié)的序號(hào)。只有 ACK 標(biāo)志位為 1 時(shí)這個(gè)字段才有效。

標(biāo)志位(Flags):這 6 個(gè)標(biāo)志位是握手揮手的核心:

標(biāo)志位 含義 握手/揮手中的作用
SYN 同步序列號(hào) 發(fā)起連接,攜帶初始序列號(hào)
ACK 確認(rèn) 確認(rèn)收到對(duì)方的數(shù)據(jù)
FIN 結(jié)束 請(qǐng)求關(guān)閉連接
RST 重置 強(qiáng)制中斷連接
PSH 推送 要求接收方立即將數(shù)據(jù)交給應(yīng)用層
URG 緊急 緊急指針有效

窗口大?。╓indow,16 位):接收方告訴發(fā)送方自己還能接收多少字節(jié)的數(shù)據(jù)。配合 Window Scale 選項(xiàng)可以擴(kuò)展到 30 位。

2.3 TCP Options

握手階段的 SYN 包通常攜帶以下 Options:

MSS (Maximum Segment Size)  : 通告對(duì)方自己能接收的最大報(bào)文段長(zhǎng)度,通常 1460(以太網(wǎng) MTU 1500 - IP頭20 - TCP頭20)
Window Scale         : 窗口縮放因子,允許窗口大小超過 65535
SACK Permitted        : 告知對(duì)方支持選擇性確認(rèn)
Timestamps          : 用于 RTT 計(jì)算和 PAWS(防止序列號(hào)回繞)

三、三次握手詳細(xì)過程

3.1 握手全景

三次握手的本質(zhì)是:雙方交換初始序列號(hào)(ISN),并確認(rèn)對(duì)方的接收能力。

  客戶端                     服務(wù)端
   |                        |
   | [CLOSED]              [LISTEN] |
   |                        |
   |----------- SYN, Seq=x ----------------------->|
   | [SYN_SENT]                  |
   |                  [SYN_RCVD] |
   |<---------- SYN+ACK, Seq=y, Ack=x+1 ----------|
? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? |----------- ACK, Seq=x+1, Ack=y+1 ----------->|
   | [ESTABLISHED]         [ESTABLISHED] |
   |                        |

3.2 逐包拆解

第一次握手:客戶端發(fā)送 SYN

客戶端調(diào)用connect()系統(tǒng)調(diào)用,內(nèi)核構(gòu)造一個(gè) SYN 報(bào)文發(fā)出去:

標(biāo)志位:SYN=1

序列號(hào):Seq=x(隨機(jī)生成的 ISN)

確認(rèn)號(hào):Ack=0(此時(shí)還沒有需要確認(rèn)的數(shù)據(jù))

Options:MSS=1460, WS=7, SACK_PERM, TSval=xxx

客戶端狀態(tài)從 CLOSED 變?yōu)?strong>SYN_SENT。

Wireshark 中看到的樣子:

No. Time   Source    Destination  Protocol Info
1  0.000000 192.168.1.10 10.0.0.1   TCP    54321 > 443 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 WS=128 SACK_PERM TSval=1234567

注意 Wireshark 默認(rèn)顯示的是相對(duì)序列號(hào)(從 0 開始),實(shí)際的 ISN 是一個(gè) 32 位隨機(jī)數(shù)??梢栽?Edit -> Preferences -> Protocols -> TCP 中關(guān)閉 "Relative sequence numbers" 查看真實(shí)值。

第二次握手:服務(wù)端回復(fù) SYN+ACK

服務(wù)端收到 SYN 后,從半連接隊(duì)列(SYN Queue)中分配一個(gè)條目,構(gòu)造 SYN+ACK 報(bào)文:

標(biāo)志位:SYN=1, ACK=1

序列號(hào):Seq=y(服務(wù)端自己的 ISN)

確認(rèn)號(hào):Ack=x+1(確認(rèn)收到客戶端的 SYN,期望下一個(gè)字節(jié)是 x+1)

Options:MSS=1460, WS=7, SACK_PERM, TSval=yyy

服務(wù)端狀態(tài)從 LISTEN 變?yōu)?strong>SYN_RCVD。

No. Time   Source    Destination  Protocol Info
2  0.000543 10.0.0.1   192.168.1.10 TCP    443 > 54321 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=1460 WS=128 SACK_PERM

第三次握手:客戶端發(fā)送 ACK

客戶端收到 SYN+ACK 后,connect()返回成功,同時(shí)發(fā)送最后一個(gè) ACK:

標(biāo)志位:ACK=1

序列號(hào):Seq=x+1

確認(rèn)號(hào):Ack=y+1(確認(rèn)收到服務(wù)端的 SYN)

客戶端狀態(tài)變?yōu)?strong>ESTABLISHED。服務(wù)端收到這個(gè) ACK 后,從半連接隊(duì)列移到全連接隊(duì)列(Accept Queue),狀態(tài)也變?yōu)?strong>ESTABLISHED。

No. Time   Source    Destination  Protocol Info
3  0.000012 192.168.1.10 10.0.0.1   TCP    54321 > 443 [ACK] Seq=1 Ack=1 Win=65536 Len=0

這個(gè) ACK 包是可以攜帶數(shù)據(jù)的(TCP Fast Open 就利用了這一點(diǎn)),但通常情況下 Len=0。

3.3 為什么是三次而不是兩次

這是面試高頻問題,標(biāo)準(zhǔn)答案有兩個(gè)層面:

層面一:防止歷史連接的初始化

假設(shè)只有兩次握手,客戶端發(fā)了一個(gè) SYN 包因?yàn)榫W(wǎng)絡(luò)延遲滯留在網(wǎng)絡(luò)中,客戶端超時(shí)后重新發(fā)起連接并完成通信。之后那個(gè)滯留的 SYN 包到達(dá)服務(wù)端,服務(wù)端以為是新連接請(qǐng)求,直接進(jìn)入 ESTABLISHED 狀態(tài)分配資源——但客戶端根本不知道這個(gè)連接的存在。三次握手中,服務(wù)端回復(fù) SYN+ACK 后必須等客戶端的 ACK 確認(rèn),客戶端收到一個(gè)不認(rèn)識(shí)的 SYN+ACK 會(huì)回復(fù) RST,避免了這個(gè)問題。

層面二:雙方都需要確認(rèn)對(duì)方的收發(fā)能力

建立可靠連接需要確認(rèn)四件事:客戶端的發(fā)送能力、客戶端的接收能力、服務(wù)端的發(fā)送能力、服務(wù)端的接收能力。三次握手剛好完成這四個(gè)確認(rèn):

第一次握手(SYN)   :服務(wù)端確認(rèn) -> 客戶端的發(fā)送能力 OK
第二次握手(SYN+ACK) :客戶端確認(rèn) -> 服務(wù)端的接收能力 OK + 服務(wù)端的發(fā)送能力 OK
第三次握手(ACK)   :服務(wù)端確認(rèn) -> 客戶端的接收能力 OK

兩次握手少了最后一步,服務(wù)端無法確認(rèn)客戶端的接收能力。

3.4 半連接隊(duì)列與全連接隊(duì)列

這兩個(gè)隊(duì)列是理解 SYN Flood 攻擊和連接建立失敗的關(guān)鍵:

半連接隊(duì)列(SYN Queue):存放收到 SYN 但還沒收到第三次 ACK 的連接,狀態(tài)為 SYN_RCVD。隊(duì)列長(zhǎng)度由tcp_max_syn_backlog控制。

全連接隊(duì)列(Accept Queue):存放已完成三次握手但還沒被accept()取走的連接,狀態(tài)為 ESTABLISHED。隊(duì)列長(zhǎng)度由min(backlog, somaxconn)決定。

# 查看半連接隊(duì)列溢出次數(shù)
netstat -s | grep"SYNs to LISTEN"

# 查看全連接隊(duì)列溢出次數(shù)
netstat -s | grep"overflowed"

# 用 ss 查看當(dāng)前隊(duì)列狀態(tài)
# Recv-Q: 當(dāng)前全連接隊(duì)列中的連接數(shù)
# Send-Q: 全連接隊(duì)列的最大長(zhǎng)度
ss -lnt | grep :443

隊(duì)列溢出時(shí)的表現(xiàn):半連接隊(duì)列滿了,新的 SYN 包會(huì)被直接丟棄(客戶端表現(xiàn)為連接超時(shí));全連接隊(duì)列滿了,服務(wù)端會(huì)根據(jù)tcp_abort_on_overflow參數(shù)決定是丟棄 ACK 還是發(fā)送 RST。

四、四次揮手詳細(xì)過程

4.1 揮手全景

TCP 連接的關(guān)閉需要四次揮手,因?yàn)?TCP 是全雙工的——每個(gè)方向的關(guān)閉需要獨(dú)立進(jìn)行。主動(dòng)關(guān)閉方發(fā) FIN 只是說"我不再發(fā)數(shù)據(jù)了",但還可以接收數(shù)據(jù),對(duì)方可能還有數(shù)據(jù)沒發(fā)完。

  主動(dòng)關(guān)閉方                   被動(dòng)關(guān)閉方
   |                        |
   | [ESTABLISHED]         [ESTABLISHED] |
   |                        |
   |----------- FIN, Seq=u ----------------------->|
   | [FIN_WAIT_1]                 |
   |                [CLOSE_WAIT]  |
   |<---------- ACK, Seq=v, Ack=u+1 --------------|
? ? ? | ?[FIN_WAIT_2] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? | ? ? ? ? ? ? ?(被動(dòng)方繼續(xù)發(fā)送剩余數(shù)據(jù)...) ? ? ? ? |
? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? |<---------- FIN, Seq=w, Ack=u+1 --------------|
? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[LAST_ACK] ? ? |
? ? ? | ?[TIME_WAIT] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
? ? ? |----------- ACK, Seq=u+1, Ack=w+1 ----------->|
   |                  [CLOSED]  |
   | (等待 2MSL)                  |
   | [CLOSED]                   |

4.2 逐包拆解

第一次揮手:主動(dòng)關(guān)閉方發(fā)送 FIN

應(yīng)用層調(diào)用close()或shutdown(SHUT_WR),內(nèi)核發(fā)送 FIN 報(bào)文:

標(biāo)志位:FIN=1, ACK=1

序列號(hào):Seq=u(當(dāng)前發(fā)送序列號(hào))

確認(rèn)號(hào):Ack=v(確認(rèn)對(duì)方最后收到的數(shù)據(jù))

主動(dòng)關(guān)閉方狀態(tài)從 ESTABLISHED 變?yōu)?strong>FIN_WAIT_1。

No. Time   Source    Destination  Protocol Info
10  5.234100 192.168.1.10 10.0.0.1   TCP    54321 > 443 [FIN, ACK] Seq=500 Ack=800 Win=65536 Len=0

第二次揮手:被動(dòng)關(guān)閉方回復(fù) ACK

被動(dòng)方內(nèi)核收到 FIN 后自動(dòng)回復(fù) ACK,應(yīng)用層通過read()返回 0 感知到對(duì)方關(guān)閉:

標(biāo)志位:ACK=1

確認(rèn)號(hào):Ack=u+1

被動(dòng)關(guān)閉方狀態(tài)變?yōu)?strong>CLOSE_WAIT,主動(dòng)關(guān)閉方收到后變?yōu)?strong>FIN_WAIT_2。

No. Time   Source    Destination  Protocol Info
11  5.234650 10.0.0.1   192.168.1.10 TCP    443 > 54321 [ACK] Seq=800 Ack=501 Win=65536 Len=0

第三次揮手:被動(dòng)關(guān)閉方發(fā)送 FIN

被動(dòng)方處理完剩余數(shù)據(jù)后調(diào)用close(),內(nèi)核發(fā)送 FIN:

標(biāo)志位:FIN=1, ACK=1

序列號(hào):Seq=w(可能在第二次和第三次揮手之間還發(fā)送了數(shù)據(jù))

被動(dòng)關(guān)閉方狀態(tài)變?yōu)?strong>LAST_ACK。

No. Time   Source    Destination  Protocol Info
15  5.340200 10.0.0.1   192.168.1.10 TCP    443 > 54321 [FIN, ACK] Seq=900 Ack=501 Win=65536 Len=0

第四次揮手:主動(dòng)關(guān)閉方回復(fù) ACK

主動(dòng)方回復(fù)最后一個(gè) ACK,進(jìn)入TIME_WAIT狀態(tài):

No. Time   Source    Destination  Protocol Info
16  5.340250 192.168.1.10 10.0.0.1   TCP    54321 > 443 [ACK] Seq=501 Ack=901 Win=65536 Len=0

被動(dòng)方收到 ACK 后直接進(jìn)入 CLOSED。主動(dòng)方需要等待 2MSL(Maximum Segment Lifetime)后才進(jìn)入 CLOSED。

4.3 四次揮手能變成三次嗎

可以。如果被動(dòng)關(guān)閉方在收到 FIN 時(shí)恰好也沒有數(shù)據(jù)要發(fā)了,內(nèi)核會(huì)把 ACK 和 FIN 合并成一個(gè)包(FIN+ACK),這就變成了三次揮手。在 Wireshark 中經(jīng)常能看到這種情況,Linux 內(nèi)核默認(rèn)開啟了 TCP 延遲確認(rèn)(Delayed ACK),會(huì)嘗試合并 ACK 和 FIN。

No. Time   Source    Destination  Protocol Info
10  5.234100 192.168.1.10 10.0.0.1   TCP    54321 > 443 [FIN, ACK] Seq=500 Ack=800
11  5.234650 10.0.0.1   192.168.1.10 TCP    443 > 54321 [FIN, ACK] Seq=800 Ack=501  <-- ACK和FIN合并
12 ? 5.234700 192.168.1.10 ?10.0.0.1 ? ? ?TCP ? ? ? 54321 > 443 [ACK] Seq=501 Ack=801

4.4 TIME_WAIT 狀態(tài)詳解

TIME_WAIT 是 TCP 狀態(tài)機(jī)中最容易引發(fā)生產(chǎn)問題的狀態(tài)。主動(dòng)關(guān)閉方在發(fā)送最后一個(gè) ACK 后進(jìn)入 TIME_WAIT,持續(xù) 2MSL(Linux 上硬編碼為 60 秒)。

為什么需要 TIME_WAIT:

確保最后一個(gè) ACK 到達(dá):如果最后的 ACK 丟失,被動(dòng)方會(huì)重傳 FIN,主動(dòng)方需要在 TIME_WAIT 狀態(tài)下重新發(fā)送 ACK。如果直接進(jìn)入 CLOSED,收到重傳的 FIN 后會(huì)回復(fù) RST,導(dǎo)致被動(dòng)方異常關(guān)閉。

讓舊連接的殘留包在網(wǎng)絡(luò)中消亡:TCP 用四元組(源IP、源端口、目的IP、目的端口)標(biāo)識(shí)連接。如果舊連接關(guān)閉后立即用相同四元組建立新連接,網(wǎng)絡(luò)中殘留的舊包可能被新連接錯(cuò)誤接收。等待 2MSL 確保舊包全部過期。

TIME_WAIT 堆積的危害:

# 查看 TIME_WAIT 連接數(shù)量
ss -s
# 或者
ss -ant | awk'{print $1}'| sort | uniq -c | sort -rn

# 典型輸出
 28453 TIME-WAIT
 1024 ESTABLISHED
  12 LISTEN
   3 FIN-WAIT-2

每個(gè) TIME_WAIT 連接占用約 0.25KB 內(nèi)存(內(nèi)核用 inet_timewait_sock 結(jié)構(gòu)體,比完整的 tcp_sock 小得多),28000 個(gè)也就 7MB,內(nèi)存不是主要問題。真正的問題是端口耗盡——客戶端的臨時(shí)端口范圍默認(rèn)是 32768-60999,總共 28232 個(gè),如果對(duì)同一個(gè)目標(biāo) IP:Port 的 TIME_WAIT 連接占滿了這個(gè)范圍,新連接就建不了了。

TIME_WAIT 優(yōu)化方案:

# 方案一:開啟 tcp_tw_reuse(推薦)
# 允許在 TIME_WAIT 狀態(tài)的端口被新的出站連接復(fù)用
# 前提是新連接的 timestamp 大于舊連接的最后 timestamp
sysctl -w net.ipv4.tcp_tw_reuse=1

# 方案二:縮短 FIN_TIMEOUT(影響 FIN_WAIT_2 超時(shí),不影響 TIME_WAIT)
sysctl -w net.ipv4.tcp_fin_timeout=15

# 方案三:擴(kuò)大臨時(shí)端口范圍
sysctl -w net.ipv4.ip_local_port_range="1024 65535"

# 方案四:使用連接池復(fù)用長(zhǎng)連接(應(yīng)用層方案,最推薦)
# HTTP Keep-Alive / gRPC 長(zhǎng)連接 / 數(shù)據(jù)庫(kù)連接池

注意:tcp_tw_recycle在 Linux 4.12 之后已經(jīng)被移除了,不要再用這個(gè)參數(shù)。它在 NAT 環(huán)境下會(huì)導(dǎo)致大量連接失敗。

五、Wireshark 抓包實(shí)戰(zhàn)

5.1 抓包準(zhǔn)備

# 在服務(wù)器上用 tcpdump 抓包保存為 pcap 文件,然后用 Wireshark 打開分析
# -i eth0: 指定網(wǎng)卡
# -s 0: 抓完整包
# -w: 保存到文件
# port 443: 只抓 443 端口的流量
sudo tcpdump -i eth0 -s 0 -w /tmp/tcp-handshake.pcap port 443

# 另一個(gè)終端發(fā)起請(qǐng)求
curl -v https://example.com

# 抓完后 Ctrl+C 停止,把 pcap 文件下載到本地用 Wireshark 打開

5.2 Wireshark 過濾器速查

Wireshark 的顯示過濾器是分析抓包的核心技能:

# 基礎(chǔ)過濾
tcp.port == 443          # 源或目的端口是 443
tcp.dstport == 80         # 目的端口是 80
ip.addr == 192.168.1.10      # 源或目的 IP

# 標(biāo)志位過濾(抓握手揮手的關(guān)鍵)
tcp.flags.syn == 1 && tcp.flags.ack == 0  # 只看 SYN 包(第一次握手)
tcp.flags.syn == 1 && tcp.flags.ack == 1  # 只看 SYN+ACK 包(第二次握手)
tcp.flags.fin == 1             # 只看 FIN 包
tcp.flags.reset == 1            # 只看 RST 包(排查異常斷連)

# 連接狀態(tài)過濾
tcp.analysis.retransmission    # 重傳包
tcp.analysis.duplicate_ack     # 重復(fù) ACK
tcp.analysis.zero_window      # 零窗口(接收方緩沖區(qū)滿)
tcp.analysis.window_update     # 窗口更新

# 組合過濾
tcp.flags.syn == 1 && ip.dst == 10.0.0.1  # 發(fā)往特定服務(wù)器的 SYN
tcp.stream eq 5               # 只看第 5 條 TCP 流

5.3 TCP 流追蹤

在 Wireshark 中右鍵任意一個(gè) TCP 包,選擇Follow -> TCP Stream,可以看到整條連接從握手到揮手的完整生命周期。這是分析單個(gè)連接問題最高效的方式。

流追蹤視圖會(huì)用不同顏色區(qū)分兩個(gè)方向的數(shù)據(jù),底部可以切換顯示格式(ASCII/Hex/Raw)。在 Stream 編號(hào)旁邊的下拉框可以快速切換不同的 TCP 流。

5.4 實(shí)戰(zhàn):分析一次完整的 HTTPS 連接

用 Wireshark 打開抓包文件后,一次完整的 HTTPS 連接包含以下階段:

包序號(hào) 方向       內(nèi)容          說明
------ ----       ----          ----
1    Client -> Server [SYN]          TCP 三次握手開始
2    Server -> Client [SYN, ACK]
3    Client -> Server [ACK]          TCP 連接建立完成
4    Client -> Server Client Hello      TLS 握手開始
5    Server -> Client Server Hello, Cert...
6    Client -> Server Key Exchange, Finished
7    Server -> Client Finished        TLS 握手完成
8    Client -> Server Application Data    加密的 HTTP 請(qǐng)求
9    Server -> Client Application Data    加密的 HTTP 響應(yīng)
10   Client -> Server [FIN, ACK]       TCP 四次揮手開始
11   Server -> Client [FIN, ACK]       合并的 FIN+ACK
12   Client -> Server [ACK]          連接關(guān)閉完成

重點(diǎn)關(guān)注包 1-3 的時(shí)間差:第一次握手到第二次握手的時(shí)間差就是一個(gè) RTT(Round Trip Time),這是評(píng)估網(wǎng)絡(luò)延遲的直接指標(biāo)。如果這個(gè)值超過 100ms,說明網(wǎng)絡(luò)延遲較高,需要考慮就近部署或 CDN 加速。

六、tcpdump 命令行抓包技巧

生產(chǎn)服務(wù)器通常沒有 GUI,tcpdump 是唯一的抓包手段。掌握 tcpdump 的過濾語(yǔ)法能大幅提升排查效率。

6.1 常用抓包命令

# 抓取指定端口的 SYN 包(只看新連接建立)
sudo tcpdump -i any'tcp[tcpflags] & (tcp-syn) != 0'and port 80 -nn

# 抓取 RST 包(排查連接異常斷開)
sudo tcpdump -i any'tcp[tcpflags] & (tcp-rst) != 0'-nn

# 抓取 SYN 但不包含 ACK 的包(純 SYN,第一次握手)
sudo tcpdump -i any'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn'-nn

# 抓取特定主機(jī)之間的流量并保存
sudo tcpdump -i eth0 host 10.0.0.1 and port 443 -s 0 -w /tmp/debug.pcap -c 10000

# 只抓包頭不抓數(shù)據(jù)(節(jié)省磁盤空間)
sudo tcpdump -i eth0 -s 96 port 3306 -w /tmp/mysql-headers.pcap

# 實(shí)時(shí)查看 TCP 標(biāo)志位和序列號(hào)
sudo tcpdump -i any port 80 -nn -S -tttt
# -nn: 不解析主機(jī)名和端口名
# -S: 顯示絕對(duì)序列號(hào)
# -tttt: 顯示完整時(shí)間戳

6.2 tcpdump 輸出解讀

# 典型的三次握手輸出
1401.123456 IP 192.168.1.10.54321 > 10.0.0.1.443: Flags [S], seq 1234567890, win 65535, options [mss 1460,sackOK,TS val 123456 ecr 0,nop,wscale 7], length 0
1401.124012 IP 10.0.0.1.443 > 192.168.1.10.54321: Flags [S.], seq 987654321, ack 1234567891, win 65535, options [mss 1460,sackOK,TS val 654321 ecr 123456,nop,wscale 7], length 0
1401.124050 IP 192.168.1.10.54321 > 10.0.0.1.443: Flags [.], ack 987654322, win 512, length 0

Flags 字段的含義:[S]= SYN,[S.]= SYN+ACK,[.]= ACK,[F.]= FIN+ACK,[R]= RST,[P.]= PSH+ACK。

6.3 高級(jí)過濾技巧

# 抓取 TCP 窗口為 0 的包(零窗口,接收方緩沖區(qū)滿)
sudo tcpdump -i any'tcp[14:2] = 0'-nn

# 抓取包含特定 TCP Option 的包(比如 Window Scale)
sudo tcpdump -i any'tcp[tcpflags] & tcp-syn != 0 and tcp[20] = 3'-nn

# 抓取大于指定長(zhǎng)度的包(排查大包問題)
sudo tcpdump -i any'tcp and greater 1400'-nn

# 按時(shí)間輪轉(zhuǎn)保存(長(zhǎng)時(shí)間抓包)
# -G 3600: 每小時(shí)輪轉(zhuǎn)一次
# -W 24: 最多保留 24 個(gè)文件
sudo tcpdump -i eth0 port 443 -w /tmp/capture-%Y%m%d-%H%M%S.pcap -G 3600 -W 24

七、TCP 重傳機(jī)制

TCP 的可靠傳輸依賴重傳機(jī)制。理解重傳對(duì)排查網(wǎng)絡(luò)丟包、延遲抖動(dòng)等問題至關(guān)重要。

7.1 超時(shí)重傳(RTO Retransmission)

發(fā)送方發(fā)出數(shù)據(jù)后啟動(dòng)一個(gè)重傳定時(shí)器(RTO,Retransmission Timeout)。如果在 RTO 時(shí)間內(nèi)沒有收到 ACK,就重傳該數(shù)據(jù)段。

RTO 的計(jì)算基于 RTT 的采樣值,Linux 使用 Jacobson 算法動(dòng)態(tài)調(diào)整:

SRTT = (1 - α) * SRTT + α * RTT_sample    (α = 1/8)
RTTVAR = (1 - β) * RTTVAR + β * |SRTT - RTT|  (β = 1/4)
RTO = SRTT + 4 * RTTVAR

RTO 的最小值是 200ms(TCP_RTO_MIN),最大值是 120s(TCP_RTO_MAX)。每次超時(shí)重傳后 RTO 翻倍(指數(shù)退避),依次是 200ms、400ms、800ms、1.6s...直到達(dá)到最大重傳次數(shù)(tcp_retries2默認(rèn) 15 次,總計(jì)約 15 分鐘)。

# 查看當(dāng)前連接的 RTO 值
ss -ti dst 10.0.0.1:443
# 輸出中的 rto:204 表示當(dāng)前 RTO 為 204ms

7.2 快速重傳(Fast Retransmit)

等 RTO 超時(shí)太慢了。快速重傳機(jī)制在收到 3 個(gè)重復(fù) ACK(Duplicate ACK)時(shí)立即重傳丟失的數(shù)據(jù)段,不用等定時(shí)器超時(shí)。

發(fā)送方                接收方
 |--- Seq=1, Len=1000 --->      |
 |--- Seq=1001, Len=1000 --->     | (丟失)
 |--- Seq=2001, Len=1000 --->     |
 |<-- ACK=1001 (Dup ACK?#1) ---------| ?收到 Seq=2001 但缺 1001,回復(fù) ACK=1001
? |--- Seq=3001, Len=1000 --->     |
 |<-- ACK=1001 (Dup ACK?#2) ---------|
? |--- Seq=4001, Len=1000 --->     |
 |<-- ACK=1001 (Dup ACK?#3) ---------| ?第 3 個(gè)重復(fù) ACK
? |--- Seq=1001, Len=1000 --->     | 快速重傳!
 |<-- ACK=5001 ----------------------| ?SACK 機(jī)制下一次確認(rèn)所有已收到的數(shù)據(jù)

在 Wireshark 中,快速重傳的包會(huì)被標(biāo)記為[TCP Fast Retransmission],重復(fù) ACK 會(huì)被標(biāo)記為[TCP Dup ACK]。

7.3 SACK(選擇性確認(rèn))

沒有 SACK 的情況下,快速重傳只能重傳一個(gè)包,后續(xù)丟失的包還得等超時(shí)。SACK 允許接收方告訴發(fā)送方"我收到了哪些數(shù)據(jù)段",發(fā)送方只需要重傳真正丟失的部分。

# 確認(rèn) SACK 是否啟用
sysctl net.ipv4.tcp_sack
# net.ipv4.tcp_sack = 1 (默認(rèn)開啟)

在 Wireshark 中查看 SACK 信息:過濾tcp.options.sack,可以看到 SACK 塊的左右邊界,精確標(biāo)識(shí)了接收方已收到的數(shù)據(jù)范圍。

八、TCP 擁塞控制:BBR vs Cubic

擁塞控制決定了 TCP 發(fā)送數(shù)據(jù)的速率。選錯(cuò)算法,帶寬利用率可能差幾倍。

8.1 Cubic(Linux 默認(rèn))

Cubic 是基于丟包的擁塞控制算法,Linux 從 2.6.19 開始默認(rèn)使用。核心思路是:沒丟包就加速,丟包了就減速。

工作階段:

慢啟動(dòng)(Slow Start):窗口從 initcwnd(默認(rèn) 10 個(gè) MSS)開始,每收到一個(gè) ACK 窗口加 1,指數(shù)增長(zhǎng)

擁塞避免(Congestion Avoidance):窗口超過 ssthresh 后改為線性增長(zhǎng)

丟包響應(yīng):檢測(cè)到丟包后,窗口乘以一個(gè)系數(shù)(Cubic 用三次函數(shù)恢復(fù))

Cubic 的問題:

在高帶寬高延遲(長(zhǎng)肥管道)網(wǎng)絡(luò)中,丟包恢復(fù)太慢,帶寬利用率低

把丟包等同于擁塞,但現(xiàn)代網(wǎng)絡(luò)中丟包可能是隨機(jī)的(無線網(wǎng)絡(luò))

緩沖區(qū)膨脹(Bufferbloat):在路由器緩沖區(qū)很大的情況下,Cubic 會(huì)把緩沖區(qū)填滿才觸發(fā)丟包,導(dǎo)致延遲飆升

8.2 BBR(Bottleneck Bandwidth and RTT)

BBR 是 Google 在 2016 年提出的擁塞控制算法,Linux 4.9 開始支持。BBR v3 在 Linux 6.x 內(nèi)核中已經(jīng)相當(dāng)成熟。

核心思路:不依賴丟包信號(hào),而是主動(dòng)探測(cè)瓶頸帶寬(BtlBw)和最小 RTT(RTprop),讓發(fā)送速率 = BtlBw,inflight 數(shù)據(jù)量 = BtlBw * RTprop。

BBR 的優(yōu)勢(shì):

高帶寬利用率:在長(zhǎng)肥管道中表現(xiàn)遠(yuǎn)優(yōu)于 Cubic

低延遲:不會(huì)填滿路由器緩沖區(qū)

抗隨機(jī)丟包:不把隨機(jī)丟包當(dāng)作擁塞信號(hào)

BBR 的注意事項(xiàng):

BBR 在與 Cubic 共存時(shí)可能搶占帶寬(公平性問題),BBR v3 對(duì)此有改善

在低延遲局域網(wǎng)中,BBR 和 Cubic 差異不大

需要內(nèi)核 6.x+ 才能用到 BBR v3 的完整特性

# 查看當(dāng)前使用的擁塞控制算法
sysctl net.ipv4.tcp_congestion_control

# 查看可用的算法
sysctl net.ipv4.tcp_available_congestion_control

# 切換到 BBR
sysctl -w net.ipv4.tcp_congestion_control=bbr

# 持久化配置
cat >> /etc/sysctl.conf <

8.3 如何選擇

場(chǎng)景 推薦算法 理由
跨地域/跨國(guó)傳輸 BBR 高延遲網(wǎng)絡(luò)下帶寬利用率遠(yuǎn)高于 Cubic
CDN 邊緣節(jié)點(diǎn) BBR 面對(duì)各種網(wǎng)絡(luò)質(zhì)量的客戶端,BBR 適應(yīng)性更強(qiáng)
數(shù)據(jù)中心內(nèi)部 Cubic 低延遲環(huán)境差異不大,Cubic 公平性更好
視頻流媒體 BBR 低延遲 + 高吞吐的組合適合實(shí)時(shí)傳輸
與大量 Cubic 流共存 Cubic 或 BBR v3 BBR v1/v2 的公平性問題在 v3 中有改善

九、最佳實(shí)踐

9.1 連接管理最佳實(shí)踐

服務(wù)端:

# /etc/sysctl.conf 推薦配置

# 全連接隊(duì)列長(zhǎng)度,配合應(yīng)用的 listen backlog 使用
net.core.somaxconn = 65535

# 半連接隊(duì)列長(zhǎng)度
net.ipv4.tcp_max_syn_backlog = 65535

# 開啟 SYN Cookie 防御 SYN Flood
net.ipv4.tcp_syncookies = 1

# TIME_WAIT 相關(guān)
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_max_tw_buckets = 262144

應(yīng)用層:

使用 HTTP/2 或 gRPC 多路復(fù)用,減少連接數(shù)

配置合理的 Keep-Alive 超時(shí),避免空閑連接占用資源

使用連接池管理數(shù)據(jù)庫(kù)和緩存連接

優(yōu)雅關(guān)閉:先shutdown(SHUT_WR)再close(),給對(duì)方發(fā)送剩余數(shù)據(jù)的機(jī)會(huì)

9.2 抓包分析最佳實(shí)踐

抓包時(shí)用 BPF 過濾器縮小范圍,避免抓到無關(guān)流量導(dǎo)致文件過大

生產(chǎn)環(huán)境抓包設(shè)置-c(包數(shù)量限制)或-G -W(時(shí)間輪轉(zhuǎn)),防止磁盤寫滿

分析時(shí)先用capinfos查看 pcap 文件概況,再用 Wireshark 的 Statistics -> Conversations 看連接分布

用tshark(Wireshark 的命令行版本)做批量分析和統(tǒng)計(jì)

# 用 tshark 統(tǒng)計(jì)重傳率
tshark -r capture.pcap -q -z io,stat,0,"tcp.analysis.retransmission"

# 用 tshark 導(dǎo)出特定流的數(shù)據(jù)
tshark -r capture.pcap -Y"tcp.stream eq 5"-w stream5.pcap

十、常見 TCP 問題排查

10.1 連接超時(shí)(Connection Timeout)

現(xiàn)象:客戶端connect()長(zhǎng)時(shí)間無響應(yīng),最終超時(shí)報(bào)錯(cuò)。

排查思路:

# 第一步:確認(rèn)服務(wù)端端口是否在監(jiān)聽
ss -lnt | grep :443

# 第二步:在客戶端抓包看 SYN 是否發(fā)出去了
sudo tcpdump -i any'tcp[tcpflags] & tcp-syn != 0'and dst host 10.0.0.1 -nn

# 第三步:在服務(wù)端抓包看 SYN 是否到達(dá)
sudo tcpdump -i any'tcp[tcpflags] & tcp-syn != 0'and dst port 443 -nn

# 第四步:檢查防火墻規(guī)則
iptables -L -n -v | grep 443
nft list ruleset | grep 443

常見原因和解決方案:

原因 診斷方法 解決方案
防火墻攔截 SYN 客戶端有 SYN 發(fā)出但服務(wù)端沒收到 檢查中間防火墻/安全組規(guī)則
半連接隊(duì)列溢出 netstat -s | grep "SYNs to LISTEN" 計(jì)數(shù)增長(zhǎng) 增大tcp_max_syn_backlog
全連接隊(duì)列溢出 netstat -s | grep "overflowed" 計(jì)數(shù)增長(zhǎng) 增大somaxconn+ 應(yīng)用 backlog
服務(wù)端 CPU 打滿 SYN+ACK 延遲回復(fù) 排查服務(wù)端性能問題
路由不通 traceroute 中間斷開 檢查路由表和網(wǎng)絡(luò)設(shè)備

10.2 RST 包排查

RST 是 TCP 的"緊急剎車",收到 RST 意味著連接被強(qiáng)制中斷。排查 RST 的關(guān)鍵是搞清楚誰(shuí)發(fā)的、為什么發(fā)。

常見 RST 場(chǎng)景:

# 場(chǎng)景一:連接不存在的端口
# 服務(wù)端沒有進(jìn)程監(jiān)聽該端口,內(nèi)核直接回復(fù) RST
curl http://10.0.0.1:9999
# 抓包看到:SYN -> RST,ACK

# 場(chǎng)景二:應(yīng)用異常關(guān)閉連接
# 應(yīng)用設(shè)置了 SO_LINGER l_onoff=1, l_linger=0,close() 時(shí)發(fā) RST 而非 FIN
# 或者應(yīng)用在接收緩沖區(qū)還有未讀數(shù)據(jù)時(shí)調(diào)用 close()

# 場(chǎng)景三:防火墻/LB 超時(shí)
# 中間設(shè)備(防火墻、負(fù)載均衡器)的連接跟蹤表超時(shí),后續(xù)包被回復(fù) RST
# 典型表現(xiàn):空閑一段時(shí)間后的第一個(gè)請(qǐng)求收到 RST

# 場(chǎng)景四:全連接隊(duì)列溢出且 tcp_abort_on_overflow=1
sysctl net.ipv4.tcp_abort_on_overflow
# 如果為 1,隊(duì)列滿時(shí)服務(wù)端對(duì)第三次握手的 ACK 回復(fù) RST

RST 排查命令:

# 抓取所有 RST 包并顯示詳細(xì)信息
sudo tcpdump -i any'tcp[tcpflags] & tcp-rst != 0'-nn -tttt

# 統(tǒng)計(jì) RST 包的來源分布
sudo tcpdump -i any'tcp[tcpflags] & tcp-rst != 0'-nn -c 1000 2>/dev/null | 
 awk'{print $3}'| cut -d. -f1-4 | sort | uniq -c | sort -rn

# 用 ss 查看連接被 RST 的統(tǒng)計(jì)
ss -s
# 關(guān)注 "reset" 相關(guān)的計(jì)數(shù)

10.3 半連接隊(duì)列溢出(SYN Flood)

SYN Flood 攻擊通過大量偽造源 IP 的 SYN 包填滿服務(wù)端的半連接隊(duì)列,導(dǎo)致正常連接無法建立。

檢測(cè)方法:

# 查看 SYN_RECV 狀態(tài)的連接數(shù)
ss -ant state syn-recv | wc -l

# 查看半連接隊(duì)列溢出計(jì)數(shù)(持續(xù)增長(zhǎng)說明有問題)
netstat -s | grep"SYNs to LISTEN"

# 查看 SYN Cookie 觸發(fā)次數(shù)
netstat -s | grep"SYN cookies"

# 用 nstat 看增量統(tǒng)計(jì)(比 netstat -s 更適合監(jiān)控)
nstat -az TcpExtListenDrops TcpExtListenOverflows TcpExtSyncookiesSent

防御方案:

# 開啟 SYN Cookie(必須開啟)
sysctl -w net.ipv4.tcp_syncookies=1

# 增大半連接隊(duì)列
sysctl -w net.ipv4.tcp_max_syn_backlog=65535

# 減少 SYN+ACK 重傳次數(shù)(加快清理無效半連接)
sysctl -w net.ipv4.tcp_synack_retries=2

# 配合 iptables 限速
iptables -A INPUT -p tcp --syn -mlimit--limit500/s --limit-burst 1000 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP

十一、內(nèi)核參數(shù)調(diào)優(yōu)完整方案

11.1 生產(chǎn)環(huán)境推薦配置

以下是經(jīng)過大量生產(chǎn)驗(yàn)證的 TCP 內(nèi)核參數(shù)配置,適用于高并發(fā) Web 服務(wù)場(chǎng)景:

# /etc/sysctl.d/99-tcp-tuning.conf

# ============ 連接隊(duì)列 ============
# 全連接隊(duì)列最大長(zhǎng)度(需要應(yīng)用 listen backlog 配合)
net.core.somaxconn = 65535
# 半連接隊(duì)列最大長(zhǎng)度
net.ipv4.tcp_max_syn_backlog = 65535

# ============ TIME_WAIT 優(yōu)化 ============
# 允許 TIME_WAIT 端口復(fù)用(僅對(duì)出站連接有效)
net.ipv4.tcp_tw_reuse = 1
# FIN_WAIT_2 超時(shí)時(shí)間(秒)
net.ipv4.tcp_fin_timeout = 15
# TIME_WAIT 狀態(tài)的最大數(shù)量
net.ipv4.tcp_max_tw_buckets = 262144
# 臨時(shí)端口范圍
net.ipv4.ip_local_port_range = 1024 65535

# ============ SYN Flood 防御 ============
net.ipv4.tcp_syncookies = 1
# SYN+ACK 重傳次數(shù)
net.ipv4.tcp_synack_retries = 2
# SYN 重傳次數(shù)(影響 connect 超時(shí)時(shí)間)
net.ipv4.tcp_syn_retries = 3

# ============ Keep-Alive ============
# 空閑多久后開始發(fā)送 Keep-Alive 探測(cè)(秒)
net.ipv4.tcp_keepalive_time = 600
# 探測(cè)間隔(秒)
net.ipv4.tcp_keepalive_intvl = 15
# 探測(cè)次數(shù),超過后斷開連接
net.ipv4.tcp_keepalive_probes = 5

# ============ 緩沖區(qū) ============
# TCP 接收緩沖區(qū)(最小值、默認(rèn)值、最大值,單位字節(jié))
net.ipv4.tcp_rmem = 4096 87380 16777216
# TCP 發(fā)送緩沖區(qū)
net.ipv4.tcp_wmem = 4096 65536 16777216
# 全局接收/發(fā)送緩沖區(qū)
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

# ============ 擁塞控制 ============
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

# ============ 其他優(yōu)化 ============
# 開啟 TCP Fast Open(客戶端和服務(wù)端都支持)
net.ipv4.tcp_fastopen = 3
# 開啟 SACK
net.ipv4.tcp_sack = 1
# 開啟窗口縮放
net.ipv4.tcp_window_scaling = 1
# 全連接隊(duì)列溢出時(shí)的行為(0=丟棄ACK,1=發(fā)RST)
# 生產(chǎn)環(huán)境建議設(shè)為 0,讓客戶端重試而非收到 RST
net.ipv4.tcp_abort_on_overflow = 0
# 應(yīng)用配置
sudo sysctl -p /etc/sysctl.d/99-tcp-tuning.conf

# 驗(yàn)證配置生效
sysctl net.core.somaxconn net.ipv4.tcp_tw_reuse net.ipv4.tcp_congestion_control

11.2 參數(shù)調(diào)優(yōu)注意事項(xiàng)

參數(shù) 踩坑點(diǎn) 建議
somaxconn 只改內(nèi)核不改應(yīng)用的 listen backlog 沒用 Nginx:listen 80 backlog=65535
tcp_tw_reuse 只對(duì)出站連接(客戶端角色)有效 服務(wù)端 TIME_WAIT 多要從應(yīng)用層解決
tcp_max_tw_buckets 超過限制后直接銷毀 TIME_WAIT,會(huì)打日志 設(shè)大一點(diǎn),別讓它觸發(fā)
tcp_keepalive_time 應(yīng)用層的 Keep-Alive 設(shè)置會(huì)覆蓋內(nèi)核參數(shù) 優(yōu)先在應(yīng)用層配置
tcp_rmem/wmem 最大值設(shè)太大會(huì)導(dǎo)致內(nèi)存占用過高 根據(jù)實(shí)際連接數(shù)和可用內(nèi)存計(jì)算
tcp_fastopen 需要客戶端和服務(wù)端都支持,且中間設(shè)備不能剝離 TFO Cookie 先在非關(guān)鍵服務(wù)上測(cè)試

11.3 Kubernetes 環(huán)境特殊處理

在 K8s 環(huán)境中,Pod 的內(nèi)核參數(shù)需要通過 securityContext 設(shè)置:

apiVersion:v1
kind:Pod
metadata:
name:web-server
spec:
securityContext:
 sysctls:
 -name:net.core.somaxconn
  value:"65535"
 -name:net.ipv4.tcp_tw_reuse
  value:"1"
 -name:net.ipv4.ip_local_port_range
  value:"1024 65535"
containers:
-name:nginx
 image:nginx:1.27

注意:K8s 默認(rèn)只允許設(shè)置 "safe" sysctls(net.ipv4.ip_local_port_range等),"unsafe" sysctls(如net.ipv4.tcp_syncookies)需要在 kubelet 配置中顯式允許。

十二、總結(jié)

12.1 技術(shù)要點(diǎn)回顧

TCP 報(bào)文格式:理解 Sequence Number、Acknowledgment Number、Flags 這三個(gè)字段是看懂抓包的基礎(chǔ)

三次握手:本質(zhì)是交換 ISN + 確認(rèn)雙方收發(fā)能力,半連接隊(duì)列和全連接隊(duì)列是生產(chǎn)問題的高發(fā)區(qū)

四次揮手:全雙工關(guān)閉需要雙向獨(dú)立進(jìn)行,TIME_WAIT 是主動(dòng)關(guān)閉方的必經(jīng)狀態(tài)

TIME_WAIT 優(yōu)化:tcp_tw_reuse+ 擴(kuò)大端口范圍 + 連接池是三板斧,tcp_tw_recycle已廢棄

Wireshark 過濾器:tcp.flags.syn、tcp.flags.reset、tcp.analysis.retransmission是排查三件套

tcpdump:-nn -S -tttt是標(biāo)準(zhǔn)參數(shù)組合,BPF 過濾器語(yǔ)法必須掌握

重傳機(jī)制:超時(shí)重傳兜底,快速重傳加速,SACK 精確定位丟失數(shù)據(jù)段

擁塞控制:跨地域選 BBR,數(shù)據(jù)中心內(nèi)部 Cubic 夠用,BBR v3 改善了公平性

內(nèi)核調(diào)優(yōu):somaxconn+tcp_max_syn_backlog+tcp_tw_reuse是高并發(fā)服務(wù)的必調(diào)參數(shù)

12.2 面試高頻問題速查

問題 關(guān)鍵答案
為什么三次握手不是兩次 防止歷史連接初始化 + 確認(rèn)雙方收發(fā)能力
為什么揮手是四次不是三次 全雙工關(guān)閉,被動(dòng)方可能還有數(shù)據(jù)要發(fā)(但可以合并為三次)
TIME_WAIT 存在的意義 確保最后 ACK 到達(dá) + 讓舊包在網(wǎng)絡(luò)中消亡
SYN Flood 怎么防御 SYN Cookie + 增大半連接隊(duì)列 + 限速
RST 和 FIN 的區(qū)別 FIN 是優(yōu)雅關(guān)閉(四次揮手),RST 是強(qiáng)制中斷(不等對(duì)方確認(rèn))
BBR 和 Cubic 的區(qū)別 Cubic 基于丟包,BBR 基于帶寬和延遲探測(cè)
全連接隊(duì)列滿了會(huì)怎樣 默認(rèn)丟棄 ACK(客戶端重試),tcp_abort_on_overflow=1時(shí)發(fā) RST

12.3 參考資料

RFC 9293 - TCP 規(guī)范(2022 年更新版,合并了多個(gè)舊 RFC)

BBR Congestion Control - Google Research

Wireshark TCP Analysis Documentation

Linux Kernel Networking - TCP Implementation

tcpdump Manual Page

附錄

A. TCP 狀態(tài)機(jī)完整圖

               +---------+ ---------   active OPEN
               | CLOSED |        -----------
               +---------+<--------- ?  ? create TCB
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? ^ ? ? ? ? ? ? ? ?  ?snd SYN
? ? ? ? ? ? ? ? ? ?passive OPEN | ? ? | ? CLOSE ? ? ? ? ? 
? ? ? ? ? ? ? ? ? ?------------ | ? ? | ---------- ? ? ?  ? 
? ? ? ? ? ? ? ? ? ? create TCB ?| ? ? | delete TCB ? ? ? ?  ? 
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? V ? ? | ? ? ? ? ? ? ? ? ? ? ? ? V
? ? ? ? ? ? ? ? ? +----------+ ? ? ? +----------+ ? ? ? +---------+
? ? ? ? ? ? ? ? ? | ?LISTEN ?| ? ? ? | FIN_WAIT | ? ? ? | SYN ? ? |
? ? ? ? ? ? ? ? ? +----------+ ? ? ? | ? ?_2 ? ?| ? ? ? | SENT ? ?|
? ? ? ?rcv SYN ? | ? ? | ? ?| ? ? ? +----------+ ? ? ? +---------+
? ? ? ---------- | ? ? | ? ?| ?CLOSE ? | ? ? ^ ? ?rcv SYN+ACK ?|
? ? ? snd SYN,ACK/ ? ? | ? ?| ------- | ? ? | ? ?---------- ? |
? ? ? ? ? ? ? ? ?/ ? ? ?| ? ?| snd FIN | ? ? | ? ? snd ACK ? ?|
? ? ? ? ? ? ? ? V ? ? ? | ? ?V ? ? ? ? | ? ? | ? ? ? ? ? ? ? ?|
? ? ? ? ?+---------+ ? ?| ?+-------+ ? | ? ? | ? ? ? ? ? ? ? ?V
? ? ? ? ?|SYN_RCVD | ? ?| ?|CLOSING| ? | ? ? | ? ? ? ? +---------+
? ? ? ? ?+---------+ ? ?| ?+-------+ ? | ? ? | ? ? ? ? | ?ESTAB ?|
? ? ? ? ? ?| rcv ACK ? ?| ?rcv ACK| ? ?| ? ? | ? ? ? ? +---------+
? ? ? ? ? ?| ------- ? ?| ?-------| rcv FIN ?| ?CLOSE ? ?| rcv FIN
? ? ? ? ? ?| x ? ? ? ? ?| ?x ? ? ?| ------- ?| ?------- ?| -------
? ? ? ? ? ?V ? ? ? ? ? ?| ? ? ? ? V snd ACK ?| ?snd FIN ?V snd ACK
? ? ? ? ?+---------+ ? ?| ?+---------+ ? ? ? | ? ? ? ? +---------+
? ? ? ? ?| ?ESTAB ?| ? ?| ?|TIME_WAIT| ? ? ? | ? ? ? ? |CLOSE_ ? |
? ? ? ? ?+---------+ ? ?| ?+---------+ ? ? ? | ? ? ? ? | ?WAIT ? |
? ? ? ? ? ? ? | ? ? ? ? | ? ?| 2MSL timeout ?| ? ? ? ? +---------+
? ? ? ? ? ? ? | ? ? ? ? | ? ?| ---------- ? ?| ? ? ? ? CLOSE |
? ? ? ? ? ? ? | ? ? ? ? | ? ?| delete TCB ? ?| ? ? ? ? ------|
? ? ? ? ? ? ? | ? ? ? ? | ? ?V ? ? ? ? ? ? ? | ? ? ? ? snd FIN
? ? ? ? ? ? ? | ? ? ? ? | +---------+ ? ? ? ?| ? ? ? ? ? ? ? V
? ? ? ? ? ? ? | ? ? ? ? +>| CLOSED |    |     +---------+
       |      +---------+    +-------->|LAST_ACK |
       |                    +---------+
       |                     rcv ACK |
       |                     --------|
       |                     x    V
       |                    +---------+
       +--------------------------------------->| CLOSED |
                           +---------+

B. 命令速查表

# 連接狀態(tài)查看
ss -ant                  # 查看所有 TCP 連接狀態(tài)
ss -s                   # TCP 連接統(tǒng)計(jì)摘要
ss -lnt                  # 查看監(jiān)聽端口和隊(duì)列狀態(tài)
ss -ant state time-wait | wc -l      # 統(tǒng)計(jì) TIME_WAIT 數(shù)量
ss -ti dst 10.0.0.1            # 查看到特定目標(biāo)的連接詳情(含 RTT/RTO)

# 抓包
tcpdump -i any port 80 -nn -S -tttt   # 標(biāo)準(zhǔn)抓包參數(shù)組合
tcpdump -i any'tcp[tcpflags] & tcp-syn != 0'-nn # 只抓 SYN 包
tcpdump -i any'tcp[tcpflags] & tcp-rst != 0'-nn # 只抓 RST 包

# 內(nèi)核統(tǒng)計(jì)
nstat -az TcpExtListenDrops        # 全連接隊(duì)列溢出次數(shù)
nstat -az TcpExtListenOverflows      # 全連接隊(duì)列溢出次數(shù)(另一個(gè)計(jì)數(shù)器)
nstat -az TcpExtTCPSynRetrans      # SYN 重傳次數(shù)
nstat -az TcpExtTCPTimeouts       # TCP 超時(shí)次數(shù)

# 內(nèi)核參數(shù)查看
sysctl -a | grep tcp           # 查看所有 TCP 相關(guān)參數(shù)
sysctl net.core.somaxconn         # 查看全連接隊(duì)列上限
sysctl net.ipv4.tcp_congestion_control  # 查看擁塞控制算法

六、總結(jié)

6.1 技術(shù)要點(diǎn)回顧

三次握手/四次揮手的狀態(tài)機(jī)是 TCP 排障的基本功。生產(chǎn)環(huán)境里遇到連接異常,第一反應(yīng)應(yīng)該是ss -ant看狀態(tài)分布,而不是盲目抓包。SYN_RECV 堆積指向半連接隊(duì)列溢出或 SYN Flood,CLOSE_WAIT 堆積說明應(yīng)用層沒有正確關(guān)閉連接,F(xiàn)IN_WAIT_2 長(zhǎng)期存在則要檢查對(duì)端是否還活著。狀態(tài)機(jī)搞清楚了,排查方向就不會(huì)跑偏。

TIME_WAIT 不是病,但大量堆積需要干預(yù)。TIME_WAIT 存在的意義是防止舊連接的延遲報(bào)文干擾新連接,2MSL 的等待時(shí)間是協(xié)議設(shè)計(jì)的一部分。真正需要處理的是短連接高并發(fā)場(chǎng)景下 TIME_WAIT 數(shù)量達(dá)到幾萬(wàn)甚至十幾萬(wàn)的情況。優(yōu)先考慮tcp_tw_reuse(安全地復(fù)用 TIME_WAIT 端口),配合連接池和長(zhǎng)連接從根源上減少連接創(chuàng)建頻率。tcp_tw_recycle在 NAT 環(huán)境下會(huì)導(dǎo)致丟包,內(nèi)核 4.12 之后已經(jīng)移除,別再用了。

BBR 擁塞控制在高延遲高丟包場(chǎng)景下優(yōu)勢(shì)明顯。傳統(tǒng)的 Cubic 算法基于丟包檢測(cè)來調(diào)整窗口,在跨地域?qū)>€、衛(wèi)星鏈路等高 RTT 場(chǎng)景下表現(xiàn)保守,帶寬利用率上不去。BBR 通過主動(dòng)探測(cè)瓶頸帶寬和最小 RTT 來驅(qū)動(dòng)發(fā)送速率,不依賴丟包信號(hào),在這類場(chǎng)景下吞吐量提升顯著。但 BBR 也不是銀彈——在淺緩沖交換機(jī)環(huán)境下可能造成較高的排隊(duì)延遲,部署前需要實(shí)測(cè)驗(yàn)證。

Wireshark 和 tcpdump 是網(wǎng)絡(luò)排障的瑞士軍刀。tcpdump 負(fù)責(zé)在服務(wù)器上輕量抓包,Wireshark 負(fù)責(zé)離線深度分析。掌握 BPF 過濾表達(dá)式、TCP 流追蹤、IO Graph、RTT 統(tǒng)計(jì)這幾個(gè)核心功能,絕大多數(shù) TCP 層面的問題都能定位到根因。關(guān)鍵是養(yǎng)成習(xí)慣:先用ss/nstat看宏觀統(tǒng)計(jì),縮小范圍后再針對(duì)性抓包,避免在海量數(shù)據(jù)里大海撈針。

6.2 進(jìn)階學(xué)習(xí)方向

QUIC 協(xié)議(HTTP/3 的傳輸層)

QUIC 把 TCP 的連接管理、TLS 握手、多路復(fù)用全部搬到了用戶態(tài) UDP 之上,從根本上消除了隊(duì)頭阻塞問題。三次握手 + TLS 1.3 握手合并為 1-RTT 甚至 0-RTT 建連,對(duì)移動(dòng)網(wǎng)絡(luò)和弱網(wǎng)環(huán)境的體驗(yàn)提升非常大。理解了 TCP 狀態(tài)機(jī)之后再看 QUIC 的連接遷移(Connection Migration)和丟包恢復(fù)機(jī)制,會(huì)更容易理解它的設(shè)計(jì)取舍。

實(shí)踐建議:用 Wireshark 4.x 抓取 HTTP/3 流量,對(duì)比同一請(qǐng)求在 TCP+TLS 1.3 和 QUIC 下的握手耗時(shí)差異。

eBPF 網(wǎng)絡(luò)追蹤(bpftrace / tcplife / tcpconnect)

傳統(tǒng)的 tcpdump 抓包開銷不小,而且只能看到報(bào)文層面的信息。eBPF 可以直接在內(nèi)核態(tài)掛載探針,零拷貝地追蹤 TCP 連接的生命周期、RTT 變化、重傳事件,開銷比抓包低一個(gè)數(shù)量級(jí)。BCC 工具集里的tcplife能實(shí)時(shí)輸出每條連接的存活時(shí)間和傳輸字節(jié)數(shù),tcpretrans能精確定位重傳發(fā)生在哪條流上,排障效率遠(yuǎn)超傳統(tǒng)方式。

實(shí)踐建議:從bpftrace -e 'kprobe:tcp_retransmit_skb { printf("retrans: %s:%d ", ntop(args->sk->__sk_common.skc_daddr), args->sk->__sk_common.skc_dport); }'這類單行腳本入手,逐步深入。

內(nèi)核網(wǎng)絡(luò)棧源碼閱讀

讀過net/ipv4/tcp_input.c和tcp_output.c之后,很多之前靠經(jīng)驗(yàn)判斷的問題都能找到確定性答案。比如 SYN Cookie 的具體實(shí)現(xiàn)邏輯、快速重傳的觸發(fā)條件、窗口縮放因子的協(xié)商過程,這些在源碼里都是幾十行代碼的事情。配合ftrace或perf跟蹤內(nèi)核函數(shù)調(diào)用路徑,能把抓包現(xiàn)象和內(nèi)核行為完整對(duì)應(yīng)起來。

推薦從 Linux 6.x 內(nèi)核入手,代碼結(jié)構(gòu)比早期版本清晰很多,注釋也更完善。

6.3 參考資料

RFC 793 - Transmission Control Protocol- TCP 協(xié)議的原始規(guī)范,三次握手和四次揮手的權(quán)威定義,狀態(tài)機(jī)圖就出自這里

RFC 8312 - CUBIC for Fast Long-Distance Networks- Linux 默認(rèn)擁塞控制算法 CUBIC 的規(guī)范,理解其凹凸函數(shù)窗口增長(zhǎng)模型

RFC 9002 - QUIC Loss Detection and Congestion Control- QUIC 的丟包檢測(cè)和擁塞控制機(jī)制,BBR 在 QUIC 中的應(yīng)用參考

Wireshark User's Guide- Wireshark 官方用戶手冊(cè),TCP 流分析和過濾器語(yǔ)法的權(quán)威參考

tcpdump & libpcap- tcpdump 手冊(cè)頁(yè),BPF 過濾表達(dá)式的完整語(yǔ)法說明

《TCP/IP 詳解 卷1:協(xié)議》(W. Richard Stevens 著) - TCP 協(xié)議學(xué)習(xí)的經(jīng)典教材,第 17-24 章覆蓋了 TCP 連接管理、重傳、擁塞控制的完整細(xì)節(jié)

Linux 內(nèi)核源碼 net/ipv4/tcp*.c- Bootlin 提供的在線內(nèi)核源碼瀏覽,直接看 TCP 實(shí)現(xiàn)比讀任何二手資料都準(zhǔn)確

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 網(wǎng)絡(luò)
    +關(guān)注

    關(guān)注

    14

    文章

    8266

    瀏覽量

    94879
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1425

    瀏覽量

    83537
  • Wireshark
    +關(guān)注

    關(guān)注

    0

    文章

    51

    瀏覽量

    6962

原文標(biāo)題:TCP 三次握手與四次揮手:Wireshark 抓包分析面試必考題

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    講一講的TCP三次握手四次揮手

    如果你學(xué)過網(wǎng)絡(luò)基礎(chǔ)知識(shí),那么你一定對(duì)TCP三次握手不陌生。今天我想用通俗的話來給大家講一講TCP三次握手
    的頭像 發(fā)表于 02-03 10:43 ?3427次閱讀
    講一講的<b class='flag-5'>TCP</b><b class='flag-5'>三次</b><b class='flag-5'>握手</b>和<b class='flag-5'>四次</b><b class='flag-5'>揮手</b>

    三次握手四次揮手你懂嗎

    程序員面試被問到“三次握手,四次揮手”怎么辦?
    發(fā)表于 04-08 07:23

    TCP三次握手過程描述

    本文檔主要描述TCP三次握手過程,一個(gè)完整的三次握手也就是 請(qǐng)求---應(yīng)答---再次確認(rèn)
    發(fā)表于 03-02 15:37 ?8次下載

    TCP/IP協(xié)議工作過程三次握手四次揮手

    )、第三次握手:Client收到確認(rèn)后,檢查ACK是否為1,如果正確則將標(biāo)志位ACK置為1,并將該數(shù)據(jù)包發(fā)送給Server,Server檢查ACK是否為1,如果正確則連接建立成功,Client
    的頭像 發(fā)表于 10-25 09:49 ?7581次閱讀

    TCP三次握手過程四次揮手過程說明

    連接 三次握手過程說明: 1. 由客戶端發(fā)送建立 TCP 連接的請(qǐng)求報(bào)文,其中報(bào)文中包含 seq 序列號(hào),是由發(fā)送端隨機(jī)生成的,并且將報(bào)文中的 SYN 字段置為 1,表示需要建立
    的頭像 發(fā)表于 03-01 12:00 ?4843次閱讀

    TCP三次握手四次揮手以及11種狀態(tài)資料下載

    電子發(fā)燒友網(wǎng)為你提供TCP三次握手四次揮手以及11種狀態(tài)資料下載的電子資料下載,更有其他相關(guān)的電路圖、源代碼、課件教程、中文資料、英文資料
    發(fā)表于 04-15 08:41 ?2次下載
    <b class='flag-5'>TCP</b><b class='flag-5'>三次</b><b class='flag-5'>握手</b>和<b class='flag-5'>四次</b><b class='flag-5'>揮手</b>以及11種狀態(tài)資料下載

    TCP三次握手四次揮手過程中的異常情況

    TCP 三次握手四次揮手過程中,途中某一步的報(bào)文丟失了,會(huì)發(fā)生什么?
    的頭像 發(fā)表于 09-05 10:23 ?2042次閱讀

    如何使用WireShark進(jìn)行TCP三次握手

    WireShark是一種非常方便的網(wǎng)絡(luò)抓包工具,下面演示,使用WireShark來抓取TCP三次握手過程。
    的頭像 發(fā)表于 11-01 09:50 ?2898次閱讀

    TCP建立連接概述及三次握手、四次揮手的流程

    具備上述個(gè)條件后A獲取B的信息是有要求的,根本上的要求是數(shù)據(jù)信道可靠,就是平時(shí)所說的可靠連接,那么如何保證連接的可靠性呢,TCP協(xié)議就是靠確認(rèn)應(yīng)答機(jī)制、超時(shí)重傳機(jī)制等保證連接可靠性的,接下來就通過TCP協(xié)議的
    的頭像 發(fā)表于 03-23 15:57 ?2068次閱讀
    <b class='flag-5'>TCP</b>建立連接概述及<b class='flag-5'>三次</b><b class='flag-5'>握手</b>、<b class='flag-5'>四次</b><b class='flag-5'>揮手</b>的流程

    說說TCP三次握手過程?為什么是三次而不是兩、四次

    說說TCP三次握手過程?為什么是三次而不是兩、四次
    的頭像 發(fā)表于 02-04 11:03 ?1918次閱讀

    TCP三次握手詳細(xì)過程

    TCP三次握手詳細(xì)過程: 1. 第一握手:SY
    的頭像 發(fā)表于 01-03 17:11 ?2158次閱讀

    TCP三次握手協(xié)議的作用

    連接,確保數(shù)據(jù)傳輸?shù)目煽啃浴?TCP三次握手協(xié)議的基本概念 TCP三次握手協(xié)議是一種用于在兩個(gè)網(wǎng)
    的頭像 發(fā)表于 01-03 17:15 ?1689次閱讀

    TCP三次握手安全性分析

    TCP(傳輸控制協(xié)議)的三次握手是建立可靠連接的重要機(jī)制,它確保了通信雙方在數(shù)據(jù)傳輸前的連接狀態(tài)是可靠和準(zhǔn)確的。然而,從安全性的角度來分析,TCP
    的頭像 發(fā)表于 01-03 18:10 ?1883次閱讀

    如何監(jiān)測(cè)TCP三次握手過程

    在計(jì)算機(jī)網(wǎng)絡(luò)中,傳輸控制協(xié)議(TCP)是確保數(shù)據(jù)可靠傳輸?shù)年P(guān)鍵協(xié)議之一。TCP通過三次握手過程來建立兩個(gè)端點(diǎn)之間的連接,這個(gè)
    的頭像 發(fā)表于 01-06 09:20 ?1580次閱讀

    TCP三次握手四次揮手,這樣解釋太通俗易懂了!

    TCP連接的建立和釋放分別通過“三次握手”和“四次揮手”來完成。三次
    的頭像 發(fā)表于 04-24 19:33 ?1571次閱讀
    <b class='flag-5'>TCP</b><b class='flag-5'>三次</b><b class='flag-5'>握手</b>和<b class='flag-5'>四次</b><b class='flag-5'>揮手</b>,這樣解釋太通俗易懂了!