HiHuo
首页
博客
手册
工具
首页
博客
手册
工具
  • 系统底层修炼

    • 操作系统核心知识学习指南
    • CPU调度与上下文切换
    • CFS调度器原理与源码
    • 内存管理与虚拟内存
    • PageCache与内存回收
    • 文件系统与IO优化
    • 零拷贝与Direct I/O
    • 网络子系统架构
    • TCP协议深度解析
    • TCP问题排查实战
    • 网络性能优化
    • epoll与IO多路复用
    • 进程与线程管理
    • Go Runtime调度器GMP模型
    • 系统性能分析方法论
    • DPDK与用户态网络栈
    • eBPF与内核可观测性
    • 综合实战案例

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

学习要点

  1. TCP状态机

    • LISTEN → SYN_RECV → ESTABLISHED
    • FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT
    • CLOSE_WAIT → LAST_ACK → CLOSED
  2. TIME_WAIT的意义

    • 确保ACK到达
    • 防止旧连接的包干扰新连接
    • 默认持续2*MSL (60秒)
  3. CLOSE_WAIT是bug

    • 表示应用未调用close()
    • 会泄漏文件描述符
    • 需要修复代码
  4. 性能调优参数

    • 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)