TCP协议知识点
一、基础概念与设计哲学
-
协议定位与历史
-
RFC 793(1981年首次定义),后续多个RFC扩展
-
传输层核心协议,位于IP层之上,应用层之下
-
面向连接:通信前需建立逻辑连接
-
可靠交付:无差错、不丢失、不重复、按序到达
-
字节流服务:无消息边界,与应用层报文分段/重组相关
-
-
核心服务特性
-
全双工通信:同一连接双向数据流
-
流量控制:接收方控制发送速率
-
拥塞控制:网络拥塞时调整发送速率
-
多路复用/解复用:通过端口号区分不同应用
-
二、报文格式详解(20-60字节)
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源端口 (16位) | 目的端口 (16位) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 序列号 (32位) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 确认号 (32位) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据偏移 | 保留 | 控制标志位 | 窗口大小 |
| (4位) | (6位)| UAPRSF (6位)| (16位) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 校验和 (16位) | 紧急指针 (16位) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 选项和填充 (变长,0-40字节) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
关键字段详解:
-
序列号(Sequence Number):本报文段第一个字节的编号,初始值(ISN)随机生成
-
确认号(Acknowledgment Number):期望收到的下一个字节序号,表示之前所有数据已接收
-
数据偏移:头部长度,单位4字节,最小5(20字节),最大15(60字节)
-
控制标志位(6位):
-
URG:紧急指针有效(很少使用)
-
ACK:确认号有效(建立连接后所有报文必须设置)
-
PSH:推送功能,接收方应立即交付数据
-
RST:重置连接,异常终止
-
SYN:同步序列号,用于建立连接
-
FIN:结束连接,释放资源
-
-
窗口大小:接收窗口大小,用于流量控制,最大65535字节(可通过窗口缩放扩展)
-
紧急指针:URG=1时有效,指示紧急数据结束位置
三、连接管理完整状态机
1. 完整的三次握手过程
客户端状态迁移:CLOSED → SYN_SENT → ESTABLISHED
服务器状态迁移:CLOSED → LISTEN → SYN_RCVD → ESTABLISHED
详细过程:
1. 客户端发送 SYN=1, seq=J
客户端:CLOSED → SYN_SENT
2. 服务器响应 SYN=1, ACK=1, seq=K, ack=J+1
服务器:LISTEN → SYN_RCVD
3. 客户端发送 ACK=1, seq=J+1, ack=K+1
客户端:SYN_SENT → ESTABLISHED
服务器:SYN_RCVD → ESTABLISHED
2. 完整的四次挥手过程(含所有中间状态)
主动关闭方A,被动关闭方B:
1. A → FIN=1, seq=u → B
A状态:ESTABLISHED → FIN_WAIT_1
2. B → ACK=1, seq=v, ack=u+1 → A
B状态:ESTABLISHED → CLOSE_WAIT
A状态:FIN_WAIT_1 → FIN_WAIT_2 (如果只有ACK)
3. B → FIN=1, ACK=1, seq=w, ack=u+1 → A
B状态:CLOSE_WAIT → LAST_ACK
4. A → ACK=1, seq=u+1, ack=w+1 → B
A状态:FIN_WAIT_2 → TIME_WAIT (等待2MSL)
B状态:LAST_ACK → CLOSED
3. TCP状态机完整图谱
+---------+
| CLOSED |
+---------+
| ^
被动打开 | | 主动打开
| |
v |
+---------+ SYN +---------+
| LISTEN |<---------------| SYN_SENT|
+---------+ +---------+
| | ^
| 接收SYN | | 发送SYN
| | |
v v |
+---------+ SYN+ACK +---------+
|SYN_RCVD|<-------------->|ESTABLISHED|
+---------+ +---------+
| | ^
| 关闭 | | 关闭
| 发送FIN | | 接收FIN
v v |
+---------+ +---------+
|FIN_WAIT_1| | CLOSE_WAIT|
+---------+ +---------+
| | ^
| 接收ACK | | 关闭
| | | 发送FIN
v v |
+---------+ +---------+
|FIN_WAIT_2| | LAST_ACK|
+---------+ +---------+
| | ^
| 接收FIN | | 接收ACK
| 发送ACK | |
v v |
+---------+ +---------+
| TIME_WAIT|-------------->| CLOSED |
+---------+ (2MSL超时) +---------+
4. 特殊状态详解
-
FIN_WAIT_1:主动关闭方发送FIN后等待ACK
-
FIN_WAIT_2:收到对FIN的ACK,等待对方的FIN
-
CLOSING :双方同时关闭的特殊状态
A → FIN → B (A进入FIN_WAIT_1) B → FIN → A (B进入CLOSING) // 几乎同时发送FIN A → ACK → B (A进入TIME_WAIT) B → ACK → A (B进入CLOSED) -
CLOSE_WAIT:被动关闭方收到FIN,等待应用层关闭
-
LAST_ACK:被动关闭方发送FIN后等待ACK
-
TIME_WAIT:
-
持续时间:2MSL(Maximum Segment Lifetime,通常2分钟)
-
作用1:确保最后的ACK能被重传
-
作用2:让旧连接的报文在网络中消失,防止混淆
-
问题:服务器大量TIME_WAIT影响性能
-
解决方案:SO_REUSEADDR套接字选项
-
四、可靠性机制深度解析
1. 序列号与确认机制
-
初始序列号(ISN)选择:基于时钟的随机算法,防止预测攻击
-
累积确认:ACK=n表示已收到n-1及之前的所有字节
-
选择性确认(SACK):
-
TCP选项字段,RFC 2018定义
-
格式:Kind=5, Length, Left Edge, Right Edge
-
允许接收方通知发送方非连续接收的数据块
接收数据:1-1000, 1501-2000, 2501-3000 SACK信息:[1501-2000], [2501-3000] -
2. 超时重传机制
-
RTT测量:
-
SRTT(平滑RTT):SRTT = α × SRTT + (1-α) × RTT_sample
-
RTTVAR(RTT变化):RTTVAR = β × RTTVAR + (1-β) × |SRTT - RTT_sample|
-
-
RTO计算:RTO = SRTT + 4 × RTTVAR
-
Karn算法:重传时不更新RTT估计(避免重传歧义)
-
时间戳选项:精确测量RTT,即使重传也能准确测量
3. 快速重传与快速恢复
触发条件:收到3个重复ACK(dup ACK)
过程:
1. 设置ssthresh = max(FlightSize/2, 2×MSS)
2. 重传丢失报文
3. 设置cwnd = ssthresh + 3×MSS(每个dup ACK表示一个报文离开网络)
4. 每收到一个额外dup ACK,cwnd增加1 MSS
5. 收到新数据的ACK,设置cwnd = ssthresh
五、流量控制:滑动窗口详解
1. 窗口结构
发送方维护:
+---------------------------------------------------+
| 已发送已确认 | 已发送未确认 | 可发送 | 不允许发送 |
+---------------------------------------------------+
^ ^ ^
LastByteAcked LastByteSent LastByteAcked + rwnd
接收方维护:
+---------------------------------------------------+
| 已接收已确认 | 可接收 | 不允许接收(窗口外) |
+---------------------------------------------------+
^ ^
NextByteExpected NextByteExpected + rwnd
2. 零窗口问题与解决
-
零窗口探测(ZWP):
-
接收方窗口为0时,发送方发送1字节探测报文
-
使用持久计时器(persist timer),指数退避重试
-
-
糊涂窗口综合征(SWS):
-
问题:发送小数据,接收方通告小窗口
-
解决方案:
-
接收方:窗口增大到MSS或缓冲区一半时才通告
-
发送方:使用Nagle算法或等待足够数据
-
-
3. 窗口缩放选项(Window Scaling)
-
RFC 1323定义,用于长肥管道(LFN)
-
选项格式:Kind=3, Length=3, Shift count
-
实际窗口 = 通告窗口 × 2^(shift count)
-
最大窗口可达1GB(理论值)
六、拥塞控制完整算法体系
1. 标准TCP Reno算法
状态变量:
- cwnd: 拥塞窗口(报文段数)
- ssthresh: 慢启动阈值
- dupACKcount: 重复ACK计数器
四个核心阶段:
1. 慢启动(Slow Start): cwnd指数增长(每RTT翻倍)
cwnd += MSS × (ACK确认的字节数/cwnd)
2. 拥塞避免(Congestion Avoidance): cwnd线性增长
cwnd += MSS × (MSS/cwnd) // 每RTT增加1 MSS
3. 快速重传(Fast Retransmit): 收到3个dup ACK
4. 快速恢复(Fast Recovery): 临时维护数据流
2. 主要变体算法对比
| 算法 | 发明时间 | 核心改进 | 适用场景 |
|---|---|---|---|
| TCP Tahoe | 1988 | 基本算法 | 已淘汰 |
| TCP Reno | 1990 | 快速恢复 | 标准实现 |
| TCP NewReno | 1999 | 改进快速恢复 | 多个丢包场景 |
| TCP BBR | 2016 | 基于瓶颈带宽和RTT | 高带宽长延迟 |
| TCP CUBIC | 2008 | 三次函数增长 | 默认Linux算法 |
| TCP Vegas | 1994 | 基于延迟预测 | 研究用途 |
3. CUBIC算法详解(Linux默认)
text
CUBIC使用函数:W(t) = C×(t-K)³ + W_max
其中:
- W_max: 丢包时的窗口大小
- K: 达到W_max所需时间,K = ³√(W_max×β/C)
- C: 缩放因子,默认0.4
- β: 乘性减小因子,默认0.7
特点:
- 在远离W_max时快速增长(凹函数)
- 接近W_max时缓慢增长(凸函数)
- 独立于RTT,公平性更好
4. BBR算法原理
text
BBR v1/v2核心状态机:
- STARTUP: 指数增长寻找BDP(带宽×延迟积)
- DRAIN: 排空STARTUP创建的队列
- PROBE_BW: 周期性地探测(+25%, -25%, 维持)
- PROBE_RTT: 每10秒降低速率测量最小RTT
关键指标:
- BtlBw: 瓶颈带宽(最近10个RTT的最大交付率)
- RTprop: 往返传播延迟(最近10秒的最小RTT)
- BDP: BtlBw × RTprop(最优飞行数据量)
七、TCP选项全面解析
1. 选项格式与类型
text
单个选项格式:
Kind (1字节) | Length (1字节) | Data (变长)
重要选项:
1. MSS(Maximum Segment Size): Kind=2, Length=4
- 声明本端能接收的最大报文段
- 默认536字节(IPv4),1220字节(IPv6)
2. 窗口缩放(Window Scale): Kind=3, Length=3
- 只在SYN报文中有效
- shift值0-14,窗口最大1GB
3. SACK允许(SACK-Permitted): Kind=4, Length=2
- 握手时协商,后续报文可用SACK选项
4. SACK信息(SACK): Kind=5, Length=变长
- 每个SACK块8字节(左右边界各4字节)
5. 时间戳(Timestamps): Kind=8, Length=10
- TSval: 发送时间戳
- TSecr: 回显时间戳
- 作用:精确RTT测量、PAWS防序号回绕
6. NOP(No-Operation): Kind=1
- 选项对齐填充
7. EOL(End of Option List): Kind=0
- 选项列表结束
2. 时间戳选项的PAWS机制
text
序号回绕问题:32位序号在10Gbps链路上34秒回绕
PAWS(Protection Against Wrapped Sequences):
- 使用时间戳作为扩展序号
- 规则:如果TSval < 最近的有效时间戳,则丢弃报文
- 时间戳单调递增(即使系统时钟跳变)
八、高级特性与优化技术
1. 保活机制(Keepalive)
text
参数(Linux默认值):
- tcp_keepalive_time = 7200秒(2小时)
- tcp_keepalive_intvl = 75秒
- tcp_keepalive_probes = 9次
工作流程:
1. 连接空闲2小时后,发送保活探测
2. 每75秒重试,最多9次
3. 总超时:2小时 + 75秒×9 ≈ 2小时11分
2. Nagle算法与Corking
text
Nagle算法规则:
IF 有未确认数据
THEN 缓存小数据直到收到ACK
ELSE
立即发送
禁用:TCP_NODELAY选项
Linux扩展:TCP_CORK选项
- 类似Nagle,但由应用层控制
- 适合HTTP响应头+体的批量发送
3. 延迟确认(Delayed ACK)
text
规则:
1. 每两个完整报文段确认一次
2. 最长延迟200ms(Linux默认40ms)
3. 有数据要发送时捎带确认
4. 广播/多播时不使用
优化:TCP_QUICKACK选项可禁用
4. 路径MTU发现(PMTUD)
text
过程:
1. 设置DF(Don't Fragment)标志
2. 发送大报文
3. 收到ICMP "Fragmentation Needed"错误
4. 减小MSS,更新路由缓存
问题:ICMP被防火墙过滤导致黑洞
解决方案:PLPMTUD(Packetization Layer Path MTU Discovery)
九、缓冲区管理与性能调优
1. 缓冲区大小计算
text
理论最优值:带宽延迟积(BDP)
BDP(字节)= 带宽(bps)× RTT(秒)/ 8
实际设置:
# Linux系统参数
net.ipv4.tcp_rmem = 4096 87380 6291456 # 最小 默认 最大
net.ipv4.tcp_wmem = 4096 16384 4194304
net.core.rmem_max = 6291456
net.core.wmem_max = 4194304
# 自动调整缓冲区(默认启用)
net.ipv4.tcp_moderate_rcvbuf = 1
2. 内存压力与公平性
-
压力状态:系统内存不足时缩减缓冲区
-
公平排队:相同RTT的流应获得相等带宽
-
RTT不公平性:标准TCP对长RTT连接不公平
十、异常处理与安全
1. 连接复位(RST)
text
发送RST的场景:
1. 到不存在的端口的连接请求
2. 异常终止连接
3. 半开连接检测(收到已关闭连接的报文)
4. 收到无效序列号的报文
RST报文:不需要ACK确认
2. SYN Flood攻击防御
text
攻击原理:伪造大量SYN不完成握手
防御机制:
1. SYN Cookie(Linux默认):
- 编码MSS、序列号到SYN-ACK的序列号
- 不分配连接资源直到收到ACK
2. SYN Cache:哈希表存储半开连接
3. SYN Proxy:代理完成握手后再与后端建立
3. 序列号随机化
text
早期问题:可预测序列号导致连接劫持
解决方案(RFC 1948):
ISN = M + F(localhost, localport, remotehost, remoteport, secret)
其中M为单调递增计数器,F为哈希函数
十一、TCP扩展与替代协议
1. Multipath TCP(MPTCP)
text
特性:
- 单个连接使用多个路径
- 向后兼容(对应用透明)
- 子流管理、调度、拥塞控制
应用场景:蜂窝/Wi-Fi切换、数据中心多路径
2. TCP Fast Open(TFO)
text
目标:减少握手延迟
过程:
1. 首次连接获取TFO Cookie
2. 后续连接SYN携带数据和Cookie
3. 服务器验证Cookie,立即响应数据
限制:仅适用于幂等请求(如HTTP GET)
3. QUIC(基于UDP的替代)
text
相比TCP优势:
- 0-RTT连接建立
- 改进的拥塞控制
- 无队头阻塞的多路复用
- 内置加密(TLS 1.3)
- 连接迁移支持
十二、性能监控与诊断
1. 关键性能指标(KPI)
text
# 使用ss -it命令查看
1. 发送/接收窗口
2. RTT/RTTVAR
3. 拥塞窗口(cwnd)
4. 慢启动阈值(ssthresh)
5. 重传超时(rto)
6. 未确认字节数(unacked)
7. 丢失恢复状态(lost)
2. 网络诊断工具链
text
1. 连接状态:netstat -ant, ss -s
2. 抓包分析:tcpdump, Wireshark
3. 流量监控:iftop, nethogs
4. 带宽测试:iperf3, netperf
5. 延迟分析:tcptraceroute, mtr
6. 缓冲区监控:ip -s link
3. Wireshark过滤与分析
text
关键过滤器:
- tcp.analysis.flags:分析标志位
- tcp.analysis.retransmission:重传报文
- tcp.analysis.zero_window:零窗口事件
- tcp.analysis.window_update:窗口更新
- tcp.analysis.duplicate_ack:重复ACK
专家信息:
- 重复ACK编号
- 乱序报文
- 窗口冻结
十三、操作系统实现差异
1. Linux vs Windows TCP实现
| 特性 | Linux | Windows |
|---|---|---|
| 默认拥塞控制 | CUBIC | CTCP(Vista+) |
| 初始窗口 | 10 MSS | 10 MSS(不同版本变化) |
| 延迟ACK时间 | 40ms | 200ms |
| TIME_WAIT回收 | SO_REUSEADDR | 快速回收选项 |
| 缓冲区自动调整 | 默认开启 | 需要手动优化 |
2. 内核参数调优示例
bash
# Linux生产环境调优示例
# 缓冲区设置
echo "net.core.rmem_max = 134217728" >> /etc/sysctl.conf
echo "net.core.wmem_max = 134217728" >> /etc/sysctl.conf
echo "net.ipv4.tcp_rmem = 4096 87380 134217728" >> /etc/sysctl.conf
echo "net.ipv4.tcp_wmem = 4096 87380 134217728" >> /etc/sysctl.conf
# 拥塞控制
echo "net.ipv4.tcp_congestion_control = bbr" >> /etc/sysctl.conf
# 连接管理
echo "net.ipv4.tcp_tw_reuse = 1" >> /etc/sysctl.conf
echo "net.ipv4.tcp_fin_timeout = 30" >> /etc/sysctl.conf
# 启用TFO(TCP Fast Open)
echo "net.ipv4.tcp_fastopen = 3" >> /etc/sysctl.conf