TCP/UDP 网络协议教程 / 15-最佳实践
15 - 最佳实践
15.1 协议选择决策树
需要传输数据
│
├─ 数据完整性必须保证?
│ ├─ 是 → 持续连接?
│ │ ├─ 是 → TCP(Web、数据库、文件传输)
│ │ └─ 否 → TCP 或 QUIC
│ └─ 否 → 实时性要求高?
│ ├─ 是 → UDP(视频、游戏)
│ └─ 否 → UDP(DNS、IoT)
│
└─ 需要广播/多播?
└─ 是 → UDP
| 场景 | 协议 | 理由 |
|---|
| Web 服务 | TCP (HTTP) / QUIC | 完整性、多路复用 |
| 数据库 | TCP 长连接 | 可靠性、连接复用 |
| 文件传输 | TCP | 完整性 |
| 视频会议 | UDP (RTP) | 低延迟 |
| 在线游戏 | UDP | 实时性 |
| DNS | UDP | 简单快速 |
| IoT | UDP (CoAP) | 轻量级 |
| 跨洋传输 | QUIC | 0-RTT、拥塞控制 |
15.2 TCP 性能优化
连接优化
"""TCP 连接优化"""
import socket
def create_optimized_tcp_socket():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 地址重用
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 禁用 Nagle(低延迟场景)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
# Keepalive
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
# 设置缓冲区
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 262144)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 262144)
return sock
内核参数优化
# /etc/sysctl.d/99-tcp-optimization.conf
# 窗口缩放和时间戳
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
# 缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 131072 16777216
net.ipv4.tcp_wmem = 4096 131072 16777216
# 连接管理
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_tw_buckets = 20000
# 拥塞控制
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_slow_start_after_idle = 0
# Keepalive
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
连接池
"""TCP 连接池"""
import socket
import queue
import threading
class TCPConnectionPool:
def __init__(self, host, port, max_size=10):
self.host = host
self.port = port
self.max_size = max_size
self.pool = queue.Queue(maxsize=max_size)
self.size = 0
self.lock = threading.Lock()
def get_connection(self):
try:
return self.pool.get_nowait()
except queue.Empty:
with self.lock:
if self.size < self.max_size:
self.size += 1
return self._create_connection()
return self.pool.get(timeout=5)
def return_connection(self, sock):
try:
self.pool.put_nowait(sock)
except queue.Full:
sock.close()
with self.lock:
self.size -= 1
def _create_connection(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
sock.connect((self.host, self.port))
return sock
15.3 UDP 性能优化
"""UDP 优化"""
import socket
def optimize_udp_socket(sock):
# 增大缓冲区
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 4 * 1024 * 1024)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 4 * 1024 * 1024)
# 安全包大小
SAFE_UDP_SIZE = 1472
# 应用层限速
class RateLimiter:
def __init__(self, rate_bps):
self.rate = rate_bps
self.tokens = rate_bps
self.last_refill = time.time()
def consume(self, bytes_count):
now = time.time()
self.tokens += (now - self.last_refill) * self.rate
self.tokens = min(self.tokens, self.rate * 2)
self.last_refill = now
if self.tokens >= bytes_count:
self.tokens -= bytes_count
return True
return False
15.4 安全配置
防火墙规则
# iptables 基本规则
# 允许必要端口
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -j DROP
# 限制 SYN Flood
iptables -A INPUT -p tcp --syn -m limit --limit 100/s --limit-burst 200 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP
# 限制 UDP 洪泛
iptables -A INPUT -p udp -m limit --limit 50/s -j ACCEPT
iptables -A INPUT -p udp -j DROP
TCP 安全参数
# 防止 SYN Flood
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_synack_retries = 2
# 防止 IP 欺骗
net.ipv4.conf.all.rp_filter = 1
# 禁止 ICMP 重定向
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
应用层安全
"""输入验证"""
import ipaddress
def validate_connection(client_addr):
ip = ipaddress.ip_address(client_addr[0])
# 检查是否是私有地址
if ip.is_private:
return True
# 黑名单检查
blacklist = {"1.2.3.4", "5.6.7.8"}
if str(ip) in blacklist:
return False
return True
def safe_recv(sock, max_size=1048576):
"""安全接收(防止内存耗尽)"""
data = sock.recv(min(max_size, 65536))
if len(data) > max_size:
raise ValueError("数据过大")
return data
15.5 监控与告警
关键指标
"""网络监控指标"""
import subprocess
def get_tcp_stats():
result = subprocess.run(['ss', '-s'], capture_output=True, text=True)
stats = {}
for line in result.stdout.split('\n'):
if 'estab' in line.lower():
stats['established'] = int(line.split()[1])
elif 'timewait' in line.lower():
stats['time_wait'] = int(line.split()[1].rstrip(','))
elif 'closewait' in line.lower():
stats['close_wait'] = int(line.split()[1].rstrip(','))
return stats
def check_alerts():
stats = get_tcp_stats()
alerts = []
if stats.get('close_wait', 0) > 100:
alerts.append(f"高 CLOSE_WAIT: {stats['close_wait']}")
if stats.get('time_wait', 0) > 10000:
alerts.append(f"高 TIME_WAIT: {stats['time_wait']}")
return alerts
15.6 问题排查清单
| 问题 | 可能原因 | 排查方法 |
|---|
| 连接被拒绝 | 服务未启动/防火墙 | nc -zv host port |
| 连接超时 | 网络不通/防火墙 | ping + traceroute |
| 传输速度慢 | 窗口小/拥塞 | ss 查看窗口 |
| TIME_WAIT 过多 | 短连接过多 | ss -s 统计 |
| CLOSE_WAIT 过多 | 应用未关闭连接 | ss -tnp 查进程 |
| 数据错误 | 粘包未处理 | 抓包分析 |
# 网络诊断命令集
ss -s # 连接统计
ss -tnp # 连接详情
sysctl net.ipv4.tcp_congestion_control # 拥塞控制算法
ip -s link show # 接口统计
ip route show # 路由表
cat /etc/resolv.conf # DNS 配置
15.7 常见编程陷阱
| 陷阱 | 说明 | 解决方案 |
|---|
| 不处理粘包 | TCP 无边界 | 实现消息定界 |
| 忽略 send 部分发送 | send 不保证全部发送 | 循环发送或 sendall |
| 不检查 recv 返回空 | 空 = 连接关闭 | if not data: break |
| 不设置超时 | recv 可能永远阻塞 | settimeout() |
| 不处理连接重置 | ConnectionResetError | try-except 捕获 |
| 不关闭 Socket | 资源泄漏 | 使用 with/try-finally |
15.8 生产环境配置模板
#!/bin/bash
# /etc/sysctl.d/99-web-server.conf
# TCP 优化
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
# 缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 131072 16777216
net.ipv4.tcp_wmem = 4096 131072 16777216
# 连接管理
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_tw_buckets = 20000
# 拥塞控制
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_slow_start_after_idle = 0
# Keepalive
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
# 安全
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
15.9 核心原则总结
1. 正确性 > 性能
先确保代码正确处理所有边界情况
2. 防御性编程
假设网络不可靠,所有 IO 操作都可能失败
3. 可观测性
记录关键连接事件,暴露监控指标
4. 优雅降级
网络异常时有降级策略
5. 最小权限
只绑定必要的地址和端口
15.10 推荐资源
书籍
- 《TCP/IP 详解 卷1》 - W. Richard Stevens
- 《UNIX 网络编程》 - W. Richard Stevens
- 《高性能浏览器网络》 - Ilya Grigorik
在线资源
🎉 恭喜完成全部教程!回顾 教程目录 或从 第01章 重新复习。