TCP三次握手与四次挥手:Wireshark抓包实战详解

admin 2026-03-09 01:27:20 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文详细讲解了TCP三次握手与四次挥手的原理,并结合Wireshark与tcpdump工具进行实战抓包演示。内容涵盖环境搭建、抓包命令详解、协议字段分析及故障排查技巧,通过图形化分析与命令行操作对照,帮助读者掌握TCP连接建立与关闭的底层细节,适用于网络故障排查与性能优化场景。 综合评分: 93 文章分类: 网络安全,安全工具,实战经验,应急响应


cover_image

TCP 三次握手与四次挥手:Wireshark 抓包实战详解

点击关注👉 点击关注👉

马哥网络安全

2026年3月8日 17:03 河南

TCP 三次握手与四次挥手:Wireshark 抓包实战详解

适用场景:网络故障排查、连接超时分析、TIME_WAIT 过多问题定位、TCP 参数调优。

环境要求:Linux 4.18+ (RHEL/CentOS 8+ / Ubuntu 20.04+),root 或 sudo 权限,Wireshark 3.0+/tcpdump 4.9+。


1️⃣ 实施步骤(核心内容)

架构与数据流说明

TCP 三次握手流程:

客户端                                 服务器
   │                                     │
   │──────── SYN (seq=x) ────────────→  │  (1) 客户端发起连接
   │                                     │
   │←───── SYN-ACK (seq=y, ack=x+1) ────│  (2) 服务器确认并同步
   │                                     │
   │──────── ACK (ack=y+1) ───────────→  │  (3) 客户端确认
   │                                     │
   │========== 连接建立,开始传输 ==========│

TCP 四次挥手流程:

客户端                                 服务器
   │                                     │
   │──────── FIN (seq=m) ─────────────→  │  (1) 客户端请求关闭
   │                                     │
   │←────── ACK (ack=m+1) ───────────────│  (2) 服务器确认
   │                                     │
   │←────── FIN (seq=n) ─────────────────│  (3) 服务器请求关闭
   │                                     │
   │──────── ACK (ack=n+1) ───────────→  │  (4) 客户端确认
   │                                     │
   │      [TIME_WAIT: 2MSL = 120秒]      │
   │                                     │
   └────────── 连接关闭 ──────────────────┘

关键组件:

  • • SYN (Synchronize):同步序列号,请求建立连接
  • • ACK (Acknowledgment):确认号,确认接收到的数据
  • • FIN (Finish):结束标志,请求关闭连接
  • • seq (Sequence Number):序列号,标识发送的数据字节
  • • ack (Acknowledgment Number):确认号,期望接收的下一个字节
  • • TIME_WAIT:主动关闭方等待 2MSL(最大报文段生存时间),默认 60 秒

Step 1: 环境准备与工具安装

目标: 安装 Wireshark/tcpdump,配置测试环境

环境信息(示例):

  • • 测试客户端:192.168.1.100 (client / 2C4G / CentOS 8.5)
  • • 测试服务器:192.168.1.200 (server / 2C4G / CentOS 8.5)
  • • 测试端口:80 (HTTP) / 443 (HTTPS) / 3306 (MySQL)
  • • 网络接口:eth0

RHEL/CentOS 命令:

# 1. 安装 tcpdump 和 Wireshark(命令行版 tshark)
yum install -y tcpdump wireshark-cli nc telnet nmap-ncat

# 2. 验证 tcpdump 版本
tcpdump --version
# 预期输出:tcpdump version 4.9.3 或更高

# 3. 检查网络接口
ip link show
# 预期输出:eth0、lo 等接口列表

# 4. 测试抓包权限
tcpdump -D
# 预期输出:
# 1.eth0 [Up, Running]
# 2.lo [Up, Running, Loopback]

# 5. 启动测试 HTTP 服务器(Python 简易服务器)
python3 -m http.server 8080 &
# 预期输出:Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...

# 6. 验证服务监听
ss -tuln | grep 8080
# 预期输出:
# tcp   LISTEN 0      5            0.0.0.0:8080         0.0.0.0:*

Ubuntu/Debian 命令:

# 1. 安装 tcpdump 和 Wireshark
apt update && apt install -y tcpdump tshark netcat-openbsd telnet

# 2. 验证安装
tcpdump --version
# 预期输出:tcpdump version 4.99.0 或更高

# 3. 启动测试服务器(使用 nc)
nc -l -p 8080 &
# 或使用 Python
python3 -m http.server 8080 &

# 4. 验证监听
ss -tuln | grep 8080
# 预期输出:tcp   LISTEN 0      5      0.0.0.0:8080      0.0.0.0:*

关键参数解释:

  1. 1. tcpdump -D:列出可用网络接口,确认抓包权限
  2. 2. ss -tuln:查看 TCP/UDP 监听端口(-t=TCP, -u=UDP, -l=LISTEN, -n=数字显示)
  3. 3. python3 -m http.server:快速启动 HTTP 服务器用于测试

执行前验证:

# 确认测试端口未被占用
ss -tuln | grep 8080
# 预期输出:无输出(端口空闲)

# 确认 tcpdump 有权限抓包
tcpdump -i eth0 -c 1
# 预期输出:抓到 1 个数据包(按 Ctrl+C 停止)

执行后验证:

# 验证服务启动成功
curl -I http://127.0.0.1:8080/
# 预期输出:
# HTTP/1.0 200 OK
# Server: SimpleHTTP/0.6 Python/3.6.8

# 验证外部可访问(如果防火墙已放行)
curl -I http://192.168.1.200:8080/
# 预期输出:HTTP/1.0 200 OK

常见错误与处理:

# 错误1:tcpdump: eth0: You don't have permission to capture on that device
# 原因:非 root 用户无抓包权限
# 解决:使用 sudo 或切换到 root 用户

# 错误2:Address already in use
# 原因:端口 8080 已被占用
# 解决:更换端口或停止占用进程
lsof -i :8080
kill&nbsp;-9 <PID>

# 错误3:No route to host
# 原因:防火墙阻止连接
# 解决:临时关闭防火墙或放行端口
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload

幂等性保障:

  • • 重复安装软件包自动跳过
  • • 重复启动服务会提示端口占用(可先停止旧进程)

回滚要点:

# 停止测试服务器
pkill -f&nbsp;"http.server 8080"

# 卸载工具(可选)
yum remove -y tcpdump wireshark-cli &nbsp;# RHEL/CentOS
apt remove --purge -y tcpdump tshark &nbsp;# Ubuntu/Debian

Step 2: 抓取三次握手数据包

目标: 使用 tcpdump 抓取完整的 TCP 三次握手过程

RHEL/CentOS 和 Ubuntu/Debian 通用命令:

# 1. 启动 tcpdump 抓包(在服务器端 192.168.1.200 执行)
tcpdump -i eth0 -nn -S -vvv&nbsp;'tcp and port 8080'&nbsp;-w /tmp/tcp_handshake.pcap &
# 参数说明:
# -i eth0: 指定网络接口
# -nn: 不解析主机名和端口名(显示 IP 和端口号)
# -S: 显示绝对序列号(不使用相对序列号)
# -vvv: 非常详细的输出
# -w: 保存到文件
# 'tcp and port 8080': 过滤规则(仅抓取 TCP 且端口为 8080 的包)

# 2. 在客户端(192.168.1.100)发起连接
curl http://192.168.1.200:8080/
# 或使用 telnet 测试
telnet 192.168.1.200 8080
# 输入 GET / HTTP/1.0 并按两次回车

# 3. 停止抓包(在服务器端)
pkill -INT tcpdump
# 或等待 tcpdump 自动停止

# 4. 查看抓包文件
ls&nbsp;-lh /tmp/tcp_handshake.pcap
# 预期输出:
# -rw-r--r-- 1 root root 2.3K Jan 20 10:30 /tmp/tcp_handshake.pcap

实时查看抓包(不保存文件):

# 方法1:tcpdump 实时输出(终端查看)
tcpdump -i eth0 -nn -S -vvv&nbsp;'tcp and port 8080'
# 预期输出(三次握手示例):
# 10:30:15.123456 IP 192.168.1.100.45678 > 192.168.1.200.8080: Flags [S], seq 1234567890, win 29200, options [mss 1460,sackOK,TS val 123456 ecr 0,nop,wscale 7], length 0
# 10:30:15.123789 IP 192.168.1.200.8080 > 192.168.1.100.45678: Flags [S.], seq 9876543210, ack 1234567891, win 28960, options [mss 1460,sackOK,TS val 789012 ecr 123456,nop,wscale 7], length 0
# 10:30:15.124012 IP 192.168.1.100.45678 > 192.168.1.200.8080: Flags [.], ack 9876543211, win 229, options [nop,nop,TS val 123457 ecr 789012], length 0

# 方法2:使用 tshark 解析(更易读)
tshark -i eth0 -f&nbsp;'tcp and port 8080'&nbsp;-Y&nbsp;'tcp.flags.syn==1 or tcp.flags.fin==1'
# 预期输出:
# &nbsp; 1 &nbsp; 0.000000 192.168.1.100 → 192.168.1.200 TCP 74 45678 → 8080 [SYN] Seq=0 Win=29200 Len=0 MSS=1460
# &nbsp; 2 &nbsp; 0.000333 192.168.1.200 → 192.168.1.100 TCP 74 8080 → 45678 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460
# &nbsp; 3 &nbsp; 0.000612 192.168.1.100 → 192.168.1.200 TCP 66 45678 → 8080 [ACK] Seq=1 Ack=1 Win=229 Len=0

关键字段解读:

  1. 1. Flags [S]:SYN 标志,表示请求建立连接(第一次握手)
  2. 2. Flags [S.]:SYN+ACK 标志,表示同步并确认(第二次握手)
  3. 3. Flags [.]:ACK 标志,表示确认(第三次握手)
  4. 4. seq 1234567890:初始序列号(ISN,Initial Sequence Number)
  5. 5. ack 1234567891:确认号 = 对方 seq + 1
  6. 6. win 29200:TCP 窗口大小(接收缓冲区大小),单位字节
  7. 7. options [mss 1460]:最大报文段大小(Maximum Segment Size)

执行前验证:

# 确认服务器正在监听
ss -tuln | grep 8080
# 预期输出:tcp &nbsp; LISTEN 0 &nbsp; &nbsp; &nbsp;5 &nbsp; &nbsp; &nbsp;0.0.0.0:8080 &nbsp; &nbsp; &nbsp;0.0.0.0:*

# 确认客户端网络可达
ping -c 3 192.168.1.200
# 预期输出:3 packets transmitted, 3 received, 0% packet loss

执行后验证:

# 统计抓包文件包数量
tcpdump -r /tmp/tcp_handshake.pcap |&nbsp;wc&nbsp;-l
# 预期输出:10-20 个包(包括握手、数据传输、挥手)

# 提取握手包(SYN/SYN-ACK/ACK)
tcpdump -r /tmp/tcp_handshake.pcap -nn&nbsp;'tcp[tcpflags] & (tcp-syn) != 0'
# 预期输出:2 个包(SYN 和 SYN-ACK)

Step 3: Wireshark 图形化分析(Windows/Linux GUI)

目标: 使用 Wireshark 详细分析三次握手和四次挥手

操作步骤:

# 1. 将抓包文件传输到 Windows 客户端(如有)
scp [email protected]:/tmp/tcp_handshake.pcap ~/Desktop/
# 或直接在 Linux 图形界面打开 Wireshark

# 2. Wireshark 打开文件
# File → Open → 选择 tcp_handshake.pcap

# 3. 应用过滤器(仅显示握手和挥手)
# 过滤器输入框输入:
tcp.flags.syn==1 or tcp.flags.fin==1

# 4. 查看三次握手详细信息
# 点击第 1 个包(SYN),查看 Packet Details 窗格:
# ▸ Transmission Control Protocol, Src Port: 45678, Dst Port: 8080
# &nbsp; ▸ Flags: 0x002 (SYN)
# &nbsp; &nbsp; &nbsp; .... .... ..1. = Syn: Set
# &nbsp; &nbsp; &nbsp; .... .... ...0 = Fin: Not set
# &nbsp; ▸ Sequence Number: 1234567890 (relative sequence number)
# &nbsp; ▸ Window: 29200
# &nbsp; ▸ Options: (20 bytes)
# &nbsp; &nbsp; &nbsp; ▸ Maximum Segment Size: 1460 bytes
# &nbsp; &nbsp; &nbsp; ▸ Window Scale: 7 (multiply by 128)
# &nbsp; &nbsp; &nbsp; ▸ Timestamps: TSval 123456, TSecr 0

# 5. 查看序列号和确认号关系
# 三次握手序列号验证:
# Packet 1 (SYN): &nbsp; &nbsp; &nbsp;seq=1234567890, ack=0
# Packet 2 (SYN-ACK): &nbsp;seq=9876543210, ack=1234567891 (=Packet1.seq+1 ✅)
# Packet 3 (ACK): &nbsp; &nbsp; &nbsp;seq=1234567891, ack=9876543211 (=Packet2.seq+1 ✅)

Wireshark 快捷操作:

# 快捷键(Windows/Linux 通用)
Ctrl+F &nbsp; &nbsp; &nbsp; &nbsp;# 查找包
Ctrl+G &nbsp; &nbsp; &nbsp; &nbsp;# 跳转到指定包编号
Ctrl+E &nbsp; &nbsp; &nbsp; &nbsp;# 显示/隐藏 Packet Details
Ctrl+Shift+P &nbsp;# 打印包
右键 → Follow → TCP Stream &nbsp;# 查看完整 TCP 会话

# 常用过滤器
tcp.stream eq 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 查看第 0 个 TCP 流
tcp.flags.syn==1 and tcp.flags.ack==0 &nbsp;# 仅 SYN 包(第一次握手)
tcp.flags.syn==1 and tcp.flags.ack==1 &nbsp;# 仅 SYN-ACK 包(第二次握手)
tcp.flags.fin==1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # 仅 FIN 包(挥手)
tcp.analysis.retransmission &nbsp; &nbsp; &nbsp;# 重传包
tcp.analysis.window_full &nbsp; &nbsp; &nbsp; &nbsp; # 窗口已满

关键字段详解:

| 字段 | 含义 | 示例值 | 说明 | | — | — | — | — | | Flags | TCP 标志位 | 0x002 (SYN) | SYN=0x02, ACK=0x10, FIN=0x01, PSH=0x08, RST=0x04 | | Seq | 序列号 | 1234567890 | 标识发送的数据字节位置 | | Ack | 确认号 | 1234567891 | 期望接收的下一个字节(对方 seq+1) | | Win | 窗口大小 | 29200 | 接收缓冲区剩余空间(字节) | | Len | 数据长度 | 0 | 握手包无数据(Len=0) | | MSS | 最大报文段 | 1460 | 单个 TCP 包最大数据长度(MTU 1500 – IP 头 20 – TCP 头 20) | | Window Scale | 窗口缩放因子 | 7 | 实际窗口 = Win × 2^7 = 29200 × 128 = 3.7MB | | Timestamps | 时间戳 | TSval 123456 | 用于计算 RTT(往返时间) |

执行后验证:

# 验证三次握手完整性(使用 tshark 命令行)
tshark -r /tmp/tcp_handshake.pcap -Y&nbsp;'tcp.flags.syn==1'&nbsp;-T fields -e frame.number -e ip.src -e ip.dst -e tcp.flags
# 预期输出:
# 1    192.168.1.100   192.168.1.200   0x0002 &nbsp;# SYN
# 2    192.168.1.200   192.168.1.100   0x0012 &nbsp;# SYN-ACK (0x02 | 0x10)

# 验证序列号连续性
tshark -r /tmp/tcp_handshake.pcap -Y&nbsp;'tcp.stream eq 0'&nbsp;-T fields -e frame.number -e tcp.seq -e tcp.ack
# 预期输出:
# 1    1234567890  0
# 2    9876543210  1234567891
# 3    1234567891  9876543211

Step 4: 抓取四次挥手数据包

目标: 抓取完整的 TCP 连接关闭过程

RHEL/CentOS 和 Ubuntu/Debian 通用命令:

# 1. 启动抓包(在服务器端)
tcpdump -i eth0 -nn -S -vvv&nbsp;'tcp and port 8080'&nbsp;-w /tmp/tcp_close.pcap &

# 2. 在客户端建立连接并主动关闭
echo"GET / HTTP/1.0"&nbsp;| nc 192.168.1.200 8080
# nc 会自动关闭连接,触发四次挥手

# 3. 停止抓包
pkill -INT tcpdump

# 4. 分析四次挥手
tcpdump -r /tmp/tcp_close.pcap -nn&nbsp;'tcp[tcpflags] & (tcp-fin) != 0'
# 预期输出(简化版):
# 10:35:20.123456 IP 192.168.1.100.45678 > 192.168.1.200.8080: Flags [F.], seq 1234567901, ack 9876543250, win 229, length 0
# 10:35:20.123789 IP 192.168.1.200.8080 > 192.168.1.100.45678: Flags [.], ack 1234567902, win 227, length 0
# 10:35:20.124012 IP 192.168.1.200.8080 > 192.168.1.100.45678: Flags [F.], seq 9876543250, ack 1234567902, win 227, length 0
# 10:35:20.124234 IP 192.168.1.100.45678 > 192.168.1.200.8080: Flags [.], ack 9876543251, win 229, length 0

# 5. 使用 tshark 详细分析
tshark -r /tmp/tcp_close.pcap -Y&nbsp;'tcp.flags.fin==1'&nbsp;-T fields -e frame.number -e frame.time_relative -e ip.src -e ip.dst -e tcp.flags
# 预期输出:
# 15    5.234567    192.168.1.100   192.168.1.200   0x0011 &nbsp;# FIN-ACK (第1次挥手)
# 17    5.234890    192.168.1.200   192.168.1.100   0x0011 &nbsp;# FIN-ACK (第3次挥手)

四次挥手详细流程:

包序号 &nbsp;时间(ms) &nbsp;源地址 → 目标地址 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 标志 &nbsp; &nbsp;seq &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ack &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;说明
------ &nbsp;-------- &nbsp;-------------------------- &nbsp;------ &nbsp;----------- &nbsp;----------- &nbsp;------------------
15 &nbsp; &nbsp; &nbsp;5234.567 &nbsp;192.168.1.100 → 200:8080 &nbsp; [F.] &nbsp; &nbsp;1234567901 &nbsp; 9876543250 &nbsp; 客户端请求关闭(第1次)
16 &nbsp; &nbsp; &nbsp;5234.890 &nbsp;192.168.1.200 → 100:45678 &nbsp;[.] &nbsp; &nbsp; 9876543250 &nbsp; 1234567902 &nbsp; 服务器确认(第2次)
17 &nbsp; &nbsp; &nbsp;5235.123 &nbsp;192.168.1.200 → 100:45678 &nbsp;[F.] &nbsp; &nbsp;9876543250 &nbsp; 1234567902 &nbsp; 服务器请求关闭(第3次)
18 &nbsp; &nbsp; &nbsp;5235.456 &nbsp;192.168.1.100 → 200:8080 &nbsp; [.] &nbsp; &nbsp; 1234567902 &nbsp; 9876543251 &nbsp; 客户端确认(第4次)
19+ &nbsp; &nbsp; 125234 &nbsp; (客户端进入 TIME_WAIT,等待 2MSL = 120秒)

关键参数解释:

  1. 1. Flags [F.]:FIN+ACK,请求关闭连接并确认之前的数据
  2. 2. TIME_WAIT 状态:主动关闭方(客户端)在最后一个 ACK 后等待 2MSL(Maximum Segment Lifetime),默认 120 秒
  3. 3. 为什么需要 TIME_WAIT?
  • • 确保最后一个 ACK 到达服务器(若丢失,服务器会重传 FIN)
  • • 防止旧连接的延迟数据包影响新连接

执行后验证:

# 验证 TIME_WAIT 状态
ss -tan | grep 8080 | grep TIME-WAIT
# 预期输出:
# TIME-WAIT &nbsp;0 &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp;192.168.1.100:45678 &nbsp; 192.168.1.200:8080

# 统计 TIME_WAIT 数量
ss -tan | grep TIME-WAIT |&nbsp;wc&nbsp;-l
# 预期输出:1-10 个(取决于并发连接数)

# 查看 TIME_WAIT 超时时间(内核参数)
cat&nbsp;/proc/sys/net/ipv4/tcp_fin_timeout
# 预期输出:60(秒)

Step 5: TCP 状态机与异常连接分析

目标: 理解 TCP 状态转换,排查常见异常状态

TCP 11 种状态:

状态名称 &nbsp; &nbsp; &nbsp; &nbsp;说明 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 谁持有
----------- &nbsp; &nbsp;---------------------------------------- &nbsp;--------
LISTEN &nbsp; &nbsp; &nbsp; &nbsp; 监听状态,等待客户端连接 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 服务器
SYN_SENT &nbsp; &nbsp; &nbsp; 客户端发送 SYN 后,等待 SYN-ACK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;客户端
SYN_RECEIVED &nbsp; 服务器收到 SYN,发送 SYN-ACK 后等待 ACK &nbsp; &nbsp;服务器
ESTABLISHED &nbsp; &nbsp;连接建立,可以传输数据 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;双方
FIN_WAIT1 &nbsp; &nbsp; &nbsp;主动关闭方发送 FIN,等待 ACK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主动方
FIN_WAIT2 &nbsp; &nbsp; &nbsp;主动关闭方收到 ACK,等待对方 FIN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 主动方
CLOSE_WAIT &nbsp; &nbsp; 被动关闭方收到 FIN,发送 ACK 后等待应用关闭 被动方
CLOSING &nbsp; &nbsp; &nbsp; &nbsp;双方同时关闭(罕见) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 双方
LAST_ACK &nbsp; &nbsp; &nbsp; 被动关闭方发送 FIN,等待最后的 ACK &nbsp; &nbsp; &nbsp; &nbsp; 被动方
TIME_WAIT &nbsp; &nbsp; &nbsp;主动关闭方收到 FIN 并发送 ACK,等待 2MSL &nbsp; 主动方
CLOSED &nbsp; &nbsp; &nbsp; &nbsp; 连接关闭 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 双方

查看当前 TCP 连接状态:

# 1. 查看所有 TCP 连接状态统计
ss -tan | awk&nbsp;'{print $1}'&nbsp;|&nbsp;sort&nbsp;|&nbsp;uniq&nbsp;-c |&nbsp;sort&nbsp;-rn
# 预期输出:
# &nbsp; &nbsp; 50 ESTAB
# &nbsp; &nbsp; 20 TIME-WAIT
# &nbsp; &nbsp; 10 LISTEN
# &nbsp; &nbsp; &nbsp;3 SYN-SENT
# &nbsp; &nbsp; &nbsp;1 State

# 2. 查看指定端口的连接状态
ss -tan state established&nbsp;'( dport = :8080 or sport = :8080 )'
# 预期输出:
# State &nbsp; &nbsp; &nbsp;Recv-Q Send-Q Local Address:Port &nbsp; Peer Address:Port
# ESTAB &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp;192.168.1.200:8080 &nbsp; 192.168.1.100:45678

# 3. 查看异常状态(SYN_SENT 过多可能遭受 SYN Flood 攻击)
ss -tan state syn-sent |&nbsp;wc&nbsp;-l
# 预期输出:0-5(正常)/ 100+(异常,可能受攻击)

# 4. 查看 CLOSE_WAIT 过多(应用未正常关闭连接)
ss -tan state close-wait |&nbsp;wc&nbsp;-l
# 预期输出:0-10(正常)/ 100+(异常,应用程序 bug)

常见异常状态排查:

# 问题1:TIME_WAIT 过多(>10000)
# 危害:占用端口资源,无法建立新连接
# 排查:
ss -tan | grep TIME-WAIT |&nbsp;wc&nbsp;-l
# 解决方案1:启用 TIME_WAIT 快速回收(内核参数)
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_tw_recycle=0 &nbsp;# 注意:tcp_tw_recycle 在 Linux 4.12+ 已废弃
echo"net.ipv4.tcp_tw_reuse = 1"&nbsp;>> /etc/sysctl.conf
sysctl -p

# 解决方案2:增大本地端口范围
sysctl -w net.ipv4.ip_local_port_range="10000 65535"
echo"net.ipv4.ip_local_port_range = 10000 65535"&nbsp;>> /etc/sysctl.conf

# 问题2:CLOSE_WAIT 过多
# 危害:应用未关闭连接,导致资源泄漏
# 排查:
ss -tan state close-wait |&nbsp;head&nbsp;-5
# 预期输出:
# CLOSE-WAIT &nbsp;0 &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp;192.168.1.200:8080 &nbsp; 192.168.1.100:45678
# 解决:修复应用程序代码,确保调用 close() 关闭连接

# 问题3:SYN_RECV 过多(可能受 SYN Flood 攻击)
# 排查:
ss -tan state syn-recv |&nbsp;wc&nbsp;-l
# 解决:启用 SYN Cookie(内核参数)
sysctl -w net.ipv4.tcp_syncookies=1
echo"net.ipv4.tcp_syncookies = 1"&nbsp;>> /etc/sysctl.conf

执行后验证:

# 验证参数生效
sysctl -a | grep -E&nbsp;'tcp_tw_reuse|ip_local_port_range|tcp_syncookies'
# 预期输出:
# net.ipv4.tcp_tw_reuse = 1
# net.ipv4.ip_local_port_range = 10000    65535
# net.ipv4.tcp_syncookies = 1

2️⃣ 最小必要原理

核心机制:

TCP 使用三次握手建立可靠连接,四次挥手安全关闭连接。

为什么是三次握手而非两次?

  • • 防止旧连接请求:若客户端发送的第一个 SYN 延迟到达,服务器回复 SYN-ACK 后建立连接,但客户端认为此连接无效,导致资源浪费。第三次握手让客户端确认”我确实要建立这个连接”。
  • • 同步双方初始序列号(ISN):客户端和服务器各自生成随机 ISN,三次握手确保双方都知道对方的 ISN。

为什么是四次挥手而非三次?

  • • TCP 全双工通信:客户端发送 FIN 关闭发送方向,但服务器可能还有数据要发送,因此需要单独发送 FIN。
  • • 流程:客户端 FIN → 服务器 ACK(此时服务器可继续发送数据)→ 服务器 FIN → 客户端 ACK。

TIME_WAIT 存在的意义:

  1. 1. 确保最后的 ACK 到达:若最后的 ACK 丢失,服务器会重传 FIN,客户端需保持连接以重新发送 ACK。
  2. 2. 防止旧数据污染新连接:等待 2MSL(120 秒)确保所有旧数据包在网络中消失。

3️⃣ 可观测性(监控 + 告警 + 性能)

监控指标

Linux 原生监控:

# 1. 实时查看 TCP 连接状态统计
watch -n 1&nbsp;'ss -tan | awk "{print \$1}" | sort | uniq -c | sort -rn'
# 预期输出:
# Every 1.0s: ss -tan | awk ...
# &nbsp; &nbsp; 150 ESTAB
# &nbsp; &nbsp; &nbsp;50 TIME-WAIT
# &nbsp; &nbsp; &nbsp;10 LISTEN
# &nbsp; &nbsp; &nbsp; 5 SYN-SENT

# 2. 监控 TIME_WAIT 数量
watch -n 5&nbsp;'ss -tan | grep TIME-WAIT | wc -l'
# 预期输出:20-100(正常)/ 1000+(异常)

# 3. 查看网络吞吐量(需安装 iftop)
yum install -y iftop &nbsp;# RHEL/CentOS
apt install -y iftop &nbsp;# Ubuntu/Debian
iftop -i eth0 -n -P
# 预期输出:实时显示每个连接的发送/接收速率

# 4. 监控 TCP 重传率
netstat -s | grep -E&nbsp;'retransmitted|segments'
# 预期输出:
# &nbsp; &nbsp; 12345678 segments sent
# &nbsp; &nbsp; 567 segments retransmitted
# 重传率 = 567 / 12345678 ≈ 0.0046% (< 1% 为正常)

# 5. 查看 TCP 缓冲区使用情况
ss -tm
# 预期输出:
# ESTAB &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp;192.168.1.200:8080 &nbsp; 192.168.1.100:45678
# &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ts sack cubic wscale:7,7 rto:204 rtt:3.5/1.5 ato:40 mss:1448 cwnd:10

Prometheus 监控配置:

# /etc/prometheus/prometheus.yml
scrape_configs:
-job_name:'node_exporter'
static_configs:
-targets:&nbsp;['192.168.1.200:9100']

# 关键 TCP 指标(node_exporter 自动采集)
# node_netstat_Tcp_CurrEstab &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 当前 ESTABLISHED 连接数
# node_netstat_Tcp_ActiveOpens &nbsp; &nbsp; &nbsp; &nbsp;# 主动打开连接数(累计)
# node_netstat_Tcp_PassiveOpens &nbsp; &nbsp; &nbsp; # 被动打开连接数(累计)
# node_netstat_Tcp_RetransSegs &nbsp; &nbsp; &nbsp; &nbsp;# 重传段数(累计)
# node_netstat_TcpExt_TCPTimeouts &nbsp; &nbsp; # 超时次数(累计)
# node_netstat_TcpExt_ListenOverflows # Listen 队列溢出次数

Prometheus 告警规则:

# /etc/prometheus/rules/tcp_alerts.yml
groups:
-name:tcp_alerts
interval:15s
rules:
# 告警1:TIME_WAIT 过多
-alert:TcpTimeWaitTooMany
expr:node_sockstat_TCP_tw>5000
for:2m
labels:
severity:warning
annotations:
summary:"TIME_WAIT 连接过多({{ $value }})"
description:"主机&nbsp;{{ $labels.instance }}&nbsp;的 TIME_WAIT 连接数超过 5000,可能影响新连接建立"

# 告警2:TCP 重传率过高
-alert:TcpRetransmitRateHigh
expr:rate(node_netstat_Tcp_RetransSegs[5m])/rate(node_netstat_Tcp_OutSegs[5m])>0.02
for:3m
labels:
severity:critical
annotations:
summary:"TCP 重传率过高({{ $value | humanizePercentage }})"
description:"主机&nbsp;{{ $labels.instance }}&nbsp;的 TCP 重传率超过 2%,网络质量异常"

# 告警3:ESTABLISHED 连接数过多
-alert:TcpEstablishedTooMany
expr:node_netstat_Tcp_CurrEstab>10000
for:5m
labels:
severity:warning
annotations:
summary:"TCP ESTABLISHED 连接数过多({{ $value }})"
description:"主机&nbsp;{{ $labels.instance }}&nbsp;的 ESTABLISHED 连接数超过 10000"

# 告警4:Listen 队列溢出
-alert:TcpListenQueueOverflow
expr:increase(node_netstat_TcpExt_ListenOverflows[5m])>10
for:2m
labels:
severity:critical
annotations:
summary:"TCP Listen 队列溢出({{ $value }}&nbsp;次)"
description:"主机&nbsp;{{ $labels.instance }}&nbsp;的 Listen 队列在 5 分钟内溢出&nbsp;{{ $value }}&nbsp;次,需增大 somaxconn"

性能基准测试

场景1:并发连接性能测试

# 工具:wrk(需提前安装)
wrk -t10 -c1000 -d30s http://192.168.1.200:8080/
# 预期输出(4C8G 节点):
# Running 30s test @ http://192.168.1.200:8080/
# &nbsp; 10 threads and 1000 connections
# &nbsp; Thread Stats &nbsp; Avg &nbsp; &nbsp; &nbsp;Stdev &nbsp; &nbsp; Max &nbsp; +/- Stdev
# &nbsp; &nbsp; Latency &nbsp; &nbsp;45.23ms &nbsp; 12.34ms &nbsp;120.45ms &nbsp; 78.90%
# &nbsp; &nbsp; Req/Sec &nbsp; &nbsp; 2.21k &nbsp; 234.56 &nbsp; &nbsp; 3.12k &nbsp; &nbsp;81.23%
# &nbsp; 663000 requests in 30.05s, 545.67MB read
# Requests/sec: &nbsp;22064.32
# Transfer/sec: &nbsp; &nbsp; 18.15MB

场景2:短连接性能测试(大量 TIME_WAIT)

# 使用 ab 测试短连接
ab -n 100000 -c 1000 http://192.168.1.200:8080/
# 预期输出:
# Requests per second: &nbsp; &nbsp;15234.56 [#/sec] (mean)
# Time per request: &nbsp; &nbsp; &nbsp; 65.632 [ms] (mean)
# Connection Times (ms)
# &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; min &nbsp;mean[+/-sd] median &nbsp; max
# Connect: &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; 15 &nbsp;12.3 &nbsp; &nbsp; 12 &nbsp; &nbsp; 120
# Processing: &nbsp; &nbsp; 1 &nbsp; 45 &nbsp;23.4 &nbsp; &nbsp; 42 &nbsp; &nbsp; 250
# Waiting: &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp; 40 &nbsp;21.2 &nbsp; &nbsp; 38 &nbsp; &nbsp; 240
# Total: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp; 60 &nbsp;28.5 &nbsp; &nbsp; 55 &nbsp; &nbsp; 320

# 测试期间监控 TIME_WAIT 数量
watch -n 1&nbsp;'ss -tan | grep TIME-WAIT | wc -l'
# 预期输出:1000-5000(短连接场景下正常)

4️⃣ 常见故障与排错

| 故障编号 | 症状 | 诊断命令 | 可能根因 | 快速修复 | 永久修复 | | — | — | — | — | — | — | | #1 | 连接建立缓慢 | ss -tan state syn-recv | wc -l | 1. SYN 队列满 2. 服务器负载高 3. 网络延迟大 | 增大 SYN 队列:sysctl -w net.ipv4.tcp_max_syn_backlog=8192 | 优化应用性能 增加服务器资源 | | #2 | TIME_WAIT 过多 | ss -tan | grep TIME-WAIT | wc -l | 1. 短连接频繁 2. 主动关闭连接过多 | 启用 tw_reuse:sysctl -w net.ipv4.tcp_tw_reuse=1 | 使用长连接(HTTP Keep-Alive) | | #3 | CLOSE_WAIT 过多 | ss -tan state close-wait | wc -l | 应用未调用 close() 关闭连接 | 重启应用释放连接 | 修复应用代码 确保正确关闭连接 | | #4 | Connection refused | telnet 192.168.1.200 8080 | 1. 服务未启动 2. 端口未监听 3. 防火墙阻止 | 启动服务:systemctl start httpd | 配置防火墙放行端口 | | #5 | Connection timeout | tcpdump -i eth0 'tcp and port 8080' | 1. 网络不通 2. SYN 包被丢弃 3. 服务器无响应 | 检查网络:ping 192.168.1.200 | 检查路由和防火墙规则 | | #6 | Connection reset | ss -tan | grep ESTAB | 1. 服务器主动发送 RST 2. 防火墙中断连接 3. 应用崩溃 | 查看应用日志 | 修复应用程序 bug 调整超时参数 | | #7 | 半连接队列满 | ss -tan state syn-recv | wc -l | SYN Flood 攻击 | 启用 SYN Cookie:sysctl -w net.ipv4.tcp_syncookies=1 | 部署防火墙过滤 增大队列大小 |

详细故障排查案例:

案例1:TIME_WAIT 过多导致无法建立新连接

# 现象:客户端连接失败
curl http://192.168.1.200:8080/
# 输出:curl: (7) Failed to connect to 192.168.1.200 port 8080: Cannot assign requested address

# 排查步骤1:检查 TIME_WAIT 数量
ss -tan | grep TIME-WAIT |&nbsp;wc&nbsp;-l
# 输出:28000(异常!系统端口范围 32768-60999,仅剩 28232-28000=232 个可用)

# 排查步骤2:查看端口范围
cat&nbsp;/proc/sys/net/ipv4/ip_local_port_range
# 输出:32768    60999

# 快速修复:启用 TIME_WAIT 复用
sysctl -w net.ipv4.tcp_tw_reuse=1
# 输出:net.ipv4.tcp_tw_reuse = 1

# 永久修复:扩大端口范围
echo"net.ipv4.ip_local_port_range = 10000 65535"&nbsp;>> /etc/sysctl.conf
sysctl -p
# 预期效果:可用端口从 28232 增加到 55535 个

# 验证修复
curl http://192.168.1.200:8080/
# 输出:HTTP/1.0 200 OK(成功)

案例2:CLOSE_WAIT 过多导致应用无法接受新连接

# 现象:应用无法接受新连接
ss -tan state close-wait |&nbsp;wc&nbsp;-l
# 输出:5000(异常!)

# 排查步骤1:查看哪些进程有 CLOSE_WAIT 连接
ss -tanp state close-wait | grep -oP&nbsp;'pid=\K\d+'&nbsp;|&nbsp;sort&nbsp;|&nbsp;uniq&nbsp;-c |&nbsp;sort&nbsp;-rn
# 输出:
# &nbsp; &nbsp;5000 12345 &nbsp;# PID 12345 的进程有 5000 个 CLOSE_WAIT 连接

# 排查步骤2:确认进程名称
ps -p 12345 -o&nbsp;comm=
# 输出:nginx(或其他应用)

# 快速修复:重启应用(临时)
systemctl restart nginx

# 永久修复:修复应用代码
# 原因:应用接收到对方的 FIN 后,未调用 close() 关闭连接
# 解决:在应用代码中确保 socket 正确关闭
# 例如(Python):
# try:
# &nbsp; &nbsp; conn, addr = server_socket.accept()
# &nbsp; &nbsp; # ... 处理请求 ...
# finally:
# &nbsp; &nbsp; conn.close() &nbsp;# 确保连接关闭

5️⃣ 变更与回滚剧本

灰度策略

场景:调整 TCP 内核参数

# 步骤1:备份当前配置
sysctl -a | grep -E&nbsp;'tcp_tw_reuse|tcp_max_syn_backlog|ip_local_port_range'&nbsp;> /tmp/tcp_params_backup.txt

# 步骤2:在测试环境验证
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
# 观察 5-10 分钟,监控连接状态

# 步骤3:生产环境灰度(先在部分节点应用)
# 仅在 192.168.1.200 应用
ssh [email protected]&nbsp;"sysctl -w net.ipv4.tcp_tw_reuse=1"

# 步骤4:全量应用
for&nbsp;host&nbsp;in&nbsp;192.168.1.{200..210};&nbsp;do
&nbsp; &nbsp; ssh root@$host"sysctl -w net.ipv4.tcp_tw_reuse=1"
done

# 步骤5:持久化配置
echo"net.ipv4.tcp_tw_reuse = 1"&nbsp;>> /etc/sysctl.conf
sysctl -p

回滚条件与命令

回滚触发条件:

  1. 1. 连接失败率超过 5%
  2. 2. TCP 重传率超过 5%
  3. 3. 应用响应时间增加超过 50%

回滚步骤:

# 恢复备份的参数
while&nbsp;IFS=&nbsp;read&nbsp;-r line;&nbsp;do
&nbsp; &nbsp; sysctl -w&nbsp;"$line"
done&nbsp;< /tmp/tcp_params_backup.txt

# 或手动恢复关键参数
sysctl -w net.ipv4.tcp_tw_reuse=0
sysctl -w net.ipv4.tcp_max_syn_backlog=512

# 重启应用(如需)
systemctl restart nginx

6️⃣ 最佳实践

1. 使用 TIME_WAIT 复用而非回收

# 推荐配置(Linux 3.10+)
sysctl -w net.ipv4.tcp_tw_reuse=1
# 不推荐:tcp_tw_recycle(已在 Linux 4.12+ 废弃,NAT 环境下有问题)

2. 调整 SYN 队列大小防止 SYN Flood

sysctl -w net.ipv4.tcp_max_syn_backlog=8192 &nbsp; &nbsp; &nbsp;# 半连接队列
sysctl -w net.core.somaxconn=8192 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 全连接队列
sysctl -w net.ipv4.tcp_syncookies=1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 启用 SYN Cookie

3. 扩大本地端口范围

sysctl -w net.ipv4.ip_local_port_range="10000 65535"
# 可用端口从 28232 增加到 55535 个

4. 启用 TCP Fast Open(减少握手延迟)

sysctl -w net.ipv4.tcp_fastopen=3 &nbsp;# 3=客户端和服务器都启用
# 效果:第二次连接可跳过三次握手,延迟降低 1 RTT

5. 监控关键指标并设置告警

# 关键指标阈值(Prometheus)
# TIME_WAIT > 5000 → 告警
# 重传率 > 2% → 告警
# CLOSE_WAIT > 1000 → 告警
# SYN_RECV > 500 → 告警(可能受攻击)

6. 使用长连接减少握手开销

# HTTP Keep-Alive 配置(Nginx)
keepalive_timeout 65; &nbsp; &nbsp; &nbsp; &nbsp;# 连接保持 65 秒
keepalive_requests 1000; &nbsp; &nbsp;&nbsp;# 单个连接最多处理 1000 个请求

7. 定期清理 CLOSE_WAIT 连接

# 监控脚本(每 5 分钟检查一次)
*/5 * * * * [ $(ss -tan state close-wait |&nbsp;wc&nbsp;-l) -gt 1000 ] && systemctl restart myapp

7️⃣ FAQ

Q1: 为什么三次握手不是两次或四次?A: 两次握手无法防止旧 SYN 请求建立无效连接;四次握手冗余(SYN 和 ACK 可合并为 SYN-ACK)。三次握手是效率与可靠性的最佳平衡。

Q2: TIME_WAIT 状态可以关闭吗?A: 不能完全关闭,但可通过 tcp_tw_reuse=1 快速复用 TIME_WAIT 连接。完全关闭会导致旧数据包污染新连接。

Q3: CLOSE_WAIT 过多如何排查应用 bug?A:

# 1. 查看哪个进程有 CLOSE_WAIT 连接
ss -tanp state close-wait | grep -oP&nbsp;'pid=\K\d+'&nbsp;|&nbsp;sort&nbsp;|&nbsp;uniq&nbsp;-c
# 2. 使用 strace 跟踪进程系统调用
strace -p <PID> -e trace=close,shutdown
# 3. 检查代码是否正确调用 close()/shutdown()

Q4: 如何区分主动关闭和被动关闭?A:

  • • 主动关闭:先发送 FIN 的一方,最终进入 TIME_WAIT 状态(等待 2MSL)
  • • 被动关闭:先收到 FIN 的一方,经过 CLOSE_WAIT → LAST_ACK → CLOSED

Q5: 为什么 tcpdump 抓到的序列号和 Wireshark 不一致?A: tcpdump 默认显示相对序列号,Wireshark 显示绝对序列号。可使用 tcpdump -S 显示绝对序列号。

Q6: 如何处理 SYN Flood 攻击?A:

# 1. 启用 SYN Cookie(无状态处理 SYN)
sysctl -w net.ipv4.tcp_syncookies=1
# 2. 增大 SYN 队列
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
# 3. 减小 SYN-ACK 重试次数
sysctl -w net.ipv4.tcp_synack_retries=1
# 4. 部署防火墙限速(iptables)
iptables -A INPUT -p tcp --syn -m&nbsp;limit&nbsp;--limit&nbsp;10/s -j ACCEPT

Q7: 短连接场景如何优化性能?A:

# 1. 启用 TIME_WAIT 复用
sysctl -w net.ipv4.tcp_tw_reuse=1
# 2. 扩大端口范围
sysctl -w net.ipv4.ip_local_port_range="10000 65535"
# 3. 启用 TCP Fast Open
sysctl -w net.ipv4.tcp_fastopen=3
# 4. 应用层改为长连接(HTTP Keep-Alive)

8️⃣ 附录:关键脚本

脚本1:TCP 连接状态监控脚本

#!/bin/bash
##############################################################################
# 文件名:tcp_monitor.sh
# 版本:v1.0.0
# 用途:监控 TCP 连接状态,输出 Prometheus 格式指标
# 使用:crontab -e → */1 * * * * /usr/local/bin/tcp_monitor.sh
##############################################################################

set&nbsp;-euo pipefail

METRICS_FILE="/var/lib/node_exporter/textfile_collector/tcp_states.prom"
mkdir&nbsp;-p&nbsp;"$(dirname&nbsp;"$METRICS_FILE")"

# 获取各状态的连接数
ESTAB=$(ss -tan state established |&nbsp;wc&nbsp;-l)
TIME_WAIT=$(ss -tan state time-wait |&nbsp;wc&nbsp;-l)
CLOSE_WAIT=$(ss -tan state close-wait |&nbsp;wc&nbsp;-l)
SYN_SENT=$(ss -tan state syn-sent |&nbsp;wc&nbsp;-l)
SYN_RECV=$(ss -tan state syn-recv |&nbsp;wc&nbsp;-l)
FIN_WAIT1=$(ss -tan state fin-wait-1 |&nbsp;wc&nbsp;-l)
FIN_WAIT2=$(ss -tan state fin-wait-2 |&nbsp;wc&nbsp;-l)
LISTEN=$(ss -tan state listen |&nbsp;wc&nbsp;-l)

# 输出 Prometheus 格式
cat&nbsp;>&nbsp;"$METRICS_FILE"&nbsp;<<EOF
# HELP tcp_connections_state TCP connections by state
# TYPE tcp_connections_state gauge
tcp_connections_state{state="established"} $ESTAB
tcp_connections_state{state="time_wait"} $TIME_WAIT
tcp_connections_state{state="close_wait"} $CLOSE_WAIT
tcp_connections_state{state="syn_sent"} $SYN_SENT
tcp_connections_state{state="syn_recv"} $SYN_RECV
tcp_connections_state{state="fin_wait1"} $FIN_WAIT1
tcp_connections_state{state="fin_wait2"} $FIN_WAIT2
tcp_connections_state{state="listen"} $LISTEN
EOF

# 计算重传率
RETRANS=$(netstat -s | grep&nbsp;'segments retransmitted'&nbsp;| awk&nbsp;'{print $1}')
SENT=$(netstat -s | grep&nbsp;'segments sent out'&nbsp;| awk&nbsp;'{print $1}')

cat&nbsp;>>&nbsp;"$METRICS_FILE"&nbsp;<<EOF
# HELP tcp_segments_total TCP segments statistics
# TYPE tcp_segments_total counter
tcp_segments_retransmitted_total $RETRANS
tcp_segments_sent_total $SENT
EOF

echo"[$(date)] TCP metrics updated: ESTAB=$ESTAB, TIME_WAIT=$TIME_WAIT, CLOSE_WAIT=$CLOSE_WAIT"

脚本2:TCP 连接异常检测与告警脚本

#!/bin/bash
##############################################################################
# 文件名:tcp_alert.sh
# 版本:v1.0.0
# 用途:检测 TCP 连接异常状态并发送告警
##############################################################################

set&nbsp;-euo pipefail

# 告警阈值
TIME_WAIT_THRESHOLD=5000
CLOSE_WAIT_THRESHOLD=1000
SYN_RECV_THRESHOLD=500

# 告警方式(修改为实际告警接口)
send_alert() {
local&nbsp;message="$1"
echo"[ALERT]&nbsp;$(date):&nbsp;$message"&nbsp;>> /var/log/tcp_alert.log
# 发送到钉钉/企业微信/邮件等(需自行实现)
# curl -X POST -d "text=$message" https://your-alert-webhook-url
}

# 检查 TIME_WAIT
TIME_WAIT=$(ss -tan state time-wait |&nbsp;wc&nbsp;-l)
if&nbsp;[&nbsp;"$TIME_WAIT"&nbsp;-gt&nbsp;"$TIME_WAIT_THRESHOLD"&nbsp;];&nbsp;then
&nbsp; &nbsp; send_alert&nbsp;"TIME_WAIT 连接数过多:$TIME_WAIT(阈值:$TIME_WAIT_THRESHOLD)"
fi

# 检查 CLOSE_WAIT
CLOSE_WAIT=$(ss -tan state close-wait |&nbsp;wc&nbsp;-l)
if&nbsp;[&nbsp;"$CLOSE_WAIT"&nbsp;-gt&nbsp;"$CLOSE_WAIT_THRESHOLD"&nbsp;];&nbsp;then
&nbsp; &nbsp; send_alert&nbsp;"CLOSE_WAIT 连接数过多:$CLOSE_WAIT(阈值:$CLOSE_WAIT_THRESHOLD),可能应用未正确关闭连接"
fi

# 检查 SYN_RECV(可能受攻击)
SYN_RECV=$(ss -tan state syn-recv |&nbsp;wc&nbsp;-l)
if&nbsp;[&nbsp;"$SYN_RECV"&nbsp;-gt&nbsp;"$SYN_RECV_THRESHOLD"&nbsp;];&nbsp;then
&nbsp; &nbsp; send_alert&nbsp;"SYN_RECV 连接数过多:$SYN_RECV(阈值:$SYN_RECV_THRESHOLD),可能遭受 SYN Flood 攻击"
fi

脚本3:自动化抓包脚本

#!/bin/bash
##############################################################################
# 文件名:tcp_capture.sh
# 版本:v1.0.0
# 用途:自动抓取指定端口的 TCP 连接(三次握手+四次挥手)
# 使用:./tcp_capture.sh 8080 60 &nbsp;# 抓取 8080 端口,持续 60 秒
##############################################################################

set&nbsp;-euo pipefail

PORT=${1:-80}
DURATION=${2:-30}
OUTPUT_DIR="/tmp/tcp_captures"
OUTPUT_FILE="${OUTPUT_DIR}/tcp_${PORT}_$(date +%Y%m%d_%H%M%S).pcap"

mkdir&nbsp;-p&nbsp;"$OUTPUT_DIR"

echo"[$(date)] 开始抓包:端口=$PORT,持续时间=$DURATION&nbsp;秒"
echo"[$(date)] 输出文件:$OUTPUT_FILE"

# 启动 tcpdump 抓包
timeout"$DURATION"&nbsp;tcpdump -i any -nn -S -vvv&nbsp;"tcp and port&nbsp;$PORT"&nbsp;-w&nbsp;"$OUTPUT_FILE"&nbsp;2>&1 |&nbsp;tee"${OUTPUT_FILE}.log"&nbsp;&
TCPDUMP_PID=$!

# 等待抓包结束
wait"$TCPDUMP_PID"&nbsp;||&nbsp;true

# 分析抓包结果
echo"[$(date)] 抓包完成,开始分析..."

# 统计包数量
TOTAL_PACKETS=$(tcpdump -r&nbsp;"$OUTPUT_FILE"&nbsp;2>/dev/null |&nbsp;wc&nbsp;-l)
SYN_PACKETS=$(tcpdump -r&nbsp;"$OUTPUT_FILE"'tcp[tcpflags] & (tcp-syn) != 0'&nbsp;2>/dev/null |&nbsp;wc&nbsp;-l)
FIN_PACKETS=$(tcpdump -r&nbsp;"$OUTPUT_FILE"'tcp[tcpflags] & (tcp-fin) != 0'&nbsp;2>/dev/null |&nbsp;wc&nbsp;-l)

echo"========== 抓包统计 =========="
echo"总包数:$TOTAL_PACKETS"
echo"SYN 包数:$SYN_PACKETS(包括 SYN 和 SYN-ACK)"
echo"FIN 包数:$FIN_PACKETS"
echo"文件路径:$OUTPUT_FILE"
echo"文件大小:$(du -h&nbsp;"$OUTPUT_FILE"&nbsp;| cut -f1)"

# 导出可读的文本格式
tcpdump -r&nbsp;"$OUTPUT_FILE"&nbsp;-nn -tttt >&nbsp;"${OUTPUT_FILE}.txt"
echo"文本格式已导出:${OUTPUT_FILE}.txt"

9️⃣ 扩展阅读

官方文档:

  • • TCP RFC 793(原始规范):https://datatracker.ietf.org/doc/html/rfc793
  • • TCP Fast Open RFC 7413:https://datatracker.ietf.org/doc/html/rfc7413
  • • Linux 内核 TCP 参数文档:https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

深入技术博客:

  • • Cloudflare:Why We Can’t Have Nice Things (TIME_WAIT):https://blog.cloudflare.com/this-is-strictly-a-violation-of-the-tcp-specification/
  • • Wireshark 官方教程:https://www.wireshark.org/docs/wsug_html_chunked/
  • • TCP 状态机详解(图文):https://www.rfc-editor.org/rfc/rfc793#section-3.2

工具下载:

  • • Wireshark:https://www.wireshark.org/download.html
  • • tcpdump:https://www.tcpdump.org/
  • • tshark(命令行版 Wireshark):yum install wireshark-cli / apt install tshark

社区资源:

  • • Stack Overflow TCP 标签:https://stackoverflow.com/questions/tagged/tcp
  • • Wireshark Q&A:https://ask.wireshark.org/

文末福利

网络监控是保障网络系统和数据安全的重要手段,能够帮助运维人员及时发现并应对各种问题,及时发现并解决,从而确保网络的顺畅运行。

谢谢一路支持,给大家分享6款开源免费的网络监控工具,并准备了对应的资料文档,建议运维工程师收藏(文末一键领取)。

备注:【监控合集】

100%免费领取

一、zabbix

二、Prometheus

内容较多,6款常用网络监控工具(zabbix、Prometheus、Cacti、Grafana、OpenNMS、Nagios)不再一一介绍, 需要的朋友扫码备注【监控合集】,即可100%免费领取。

以上所有资料获取请扫码

备注:【监控合集】

100%免费领取

(后台不再回复,扫码一键领取)****


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:马哥网络安全 点击关注👉 点击关注👉《TCP 三次握手与四次挥手:Wireshark 抓包实战详解》

评论:0   参与:  0