TCP协议实验
本目录包含TCP协议相关的实验工具和脚本。
工具列表
1. TCP状态监控工具
文件: tcp_state_monitor.sh
功能:
- TCP连接状态统计
- TIME_WAIT监控
- CLOSE_WAIT检测
- TCP重传统计
- 端口使用情况
使用方法:
# 添加执行权限
chmod +x tcp_state_monitor.sh
# 显示所有信息
./tcp_state_monitor.sh
# 只显示TIME_WAIT
./tcp_state_monitor.sh -t
# 监控特定端口
./tcp_state_monitor.sh -p 80
# 实时监控模式
./tcp_state_monitor.sh -m 1
实验1:观察TCP三次握手
步骤1:启动抓包
sudo tcpdump -i lo -nn 'port 8080' -w handshake.pcap &
步骤2:建立连接
# 终端1:启动简单服务器
nc -l 8080
# 终端2:连接
nc localhost 8080
步骤3:分析抓包
sudo tcpdump -r handshake.pcap -nn
# 预期看到:
# 1. SYN: client -> server
# 2. SYN+ACK: server -> client
# 3. ACK: client -> server
使用Wireshark分析:
wireshark handshake.pcap
# 过滤器: tcp.flags.syn==1 or tcp.flags.ack==1
实验2:观察TCP四次挥手
步骤1:建立连接并关闭
# 启动服务器
nc -l 8080
# 客户端连接后,服务端Ctrl+C关闭
步骤2:观察状态变化
# 实时观察
watch -n 0.5 'ss -tan | grep 8080'
# 预期状态变化:
# ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT
实验3:TIME_WAIT问题模拟
场景:大量短连接
服务端:
# 简单HTTP服务器
while true; do
echo -e "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nOK" | nc -l 8080
done
客户端:
# 创建1000个短连接
for i in {1..1000}; do
curl -s http://localhost:8080 > /dev/null &
done
# 观察TIME_WAIT堆积
./tcp_state_monitor.sh -t
解决方案测试
方案1:启用tw_reuse
# 查看当前设置
sysctl net.ipv4.tcp_tw_reuse
# 启用
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
# 再次测试,观察TIME_WAIT数量
方案2:使用连接池
# 使用HTTP Keep-Alive
curl -H "Connection: keep-alive" http://localhost:8080
实验4:CLOSE_WAIT泄漏模拟
创建泄漏程序
server_leak.py:
#!/usr/bin/env python3
import socket
import time
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 9999))
sock.listen(100)
print("Server listening on port 9999")
print("This server will leak connections (not close them)")
while True:
conn, addr = sock.accept()
print(f"Accepted connection from {addr}")
# 故意不关闭连接
time.sleep(0.1)
测试泄漏
# 终端1:运行泄漏服务器
python3 server_leak.py
# 终端2:创建连接
for i in {1..10}; do
echo "test" | nc localhost 9999 &
sleep 0.5
done
# 终端3:观察CLOSE_WAIT
./tcp_state_monitor.sh -c
# 预期:看到大量CLOSE_WAIT
诊断工具
# 找出持有CLOSE_WAIT的进程
lsof -i TCP:9999 | grep CLOSE_WAIT
# 查看进程的fd
ls -l /proc/<pid>/fd
# 追踪系统调用
sudo strace -p <pid> -e trace=close,read,write
实验5:TCP重传观测
模拟丢包
# 使用tc模拟10%丢包
sudo tc qdisc add dev lo root netem loss 10%
# 发送数据
dd if=/dev/zero bs=1M count=100 | nc localhost 8080
# 观察重传
netstat -s | grep retrans
# 删除丢包规则
sudo tc qdisc del dev lo root
使用eBPF追踪重传
# 安装bcc-tools
sudo apt install bpfcc-tools
# 追踪TCP重传
sudo /usr/share/bcc/tools/tcpretrans
# 输出:
# TIME PID IP LADDR:LPORT T> RADDR:RPORT STATE
实验6:TCP性能测试
iperf3测试
# 服务端
iperf3 -s
# 客户端:测试吞吐量
iperf3 -c localhost -t 30
# 客户端:测试并发连接
iperf3 -c localhost -P 10
# 客户端:UDP测试
iperf3 -c localhost -u -b 1G
使用ss观察连接详情
# 查看TCP内部信息
ss -ti dst localhost
# 输出包含:
# rtt: 往返时延
# cwnd: 拥塞窗口
# retrans: 重传次数
# bytes_acked: 已确认字节数
实验7:拥塞控制算法对比
查看当前算法
sysctl net.ipv4.tcp_congestion_control
测试CUBIC vs BBR
步骤1:使用CUBIC
sudo sysctl -w net.ipv4.tcp_congestion_control=cubic
iperf3 -c server_ip -t 30 -J > cubic_result.json
步骤2:使用BBR
# 确保内核支持BBR (Linux 4.9+)
sudo modprobe tcp_bbr
sudo sysctl -w net.core.default_qdisc=fq
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
iperf3 -c server_ip -t 30 -J > bbr_result.json
步骤3:对比结果
# 提取吞吐量
jq '.end.sum_received.bits_per_second' cubic_result.json
jq '.end.sum_received.bits_per_second' bbr_result.json
学习要点
TCP状态机
- LISTEN → SYN_RECV → ESTABLISHED
- FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT
- CLOSE_WAIT → LAST_ACK → CLOSED
TIME_WAIT的意义
- 确保ACK到达
- 防止旧连接的包干扰新连接
- 默认持续2*MSL (60秒)
CLOSE_WAIT是bug
- 表示应用未调用close()
- 会泄漏文件描述符
- 需要修复代码
性能调优参数
- tcp_tw_reuse
- tcp_fin_timeout
- tcp_max_syn_backlog
- ip_local_port_range
故障排查流程
问题报告
↓
1. 使用ss/netstat查看连接状态
↓
2. 使用tcp_state_monitor.sh分析
↓
3. 如果TIME_WAIT多 → 调整参数或使用连接池
↓
4. 如果CLOSE_WAIT多 → 检查应用代码
↓
5. 如果重传多 → tcpdump抓包分析
↓
6. 使用eBPF深入追踪
参考资料
man tcp
man ss
man netstat
- RFC 793 (TCP Specification)