# TCP 协议详细总结


# TCP协议详细总结
TCP（Transmission Control Protocol，传输控制协议）是**OSI七层模型中传输层的核心协议**，由RFC 793定义核心规范，后续通过多个RFC补充优化。它是**面向连接、可靠交付、基于字节流、全双工**的传输层协议，核心目标是在不可靠的IP网络之上，为应用层提供稳定、有序、无差错的端到端数据传输服务。

---

## 一、TCP核心基础特性
1.  **面向连接**：通信前必须通过三次握手建立端到端的连接，通信结束后通过四次挥手释放连接，仅支持点对点单播，不支持广播/多播。
2.  **可靠交付**：保证数据无差错、不丢失、不重复、按序到达接收方，通过序号、确认、重传等机制实现。
3.  **面向字节流**：将应用层数据视为无结构的连续字节流，不保留报文边界，自动完成分片与重组，应用层无需关心底层传输细节。
4.  **全双工通信**：连接建立后，双方可同时在两个方向上独立发送和接收数据，各自维护发送缓冲区与接收缓冲区。
5.  **流量控制**：端到端的速率匹配，防止发送方发送过快导致接收方缓冲区溢出。
6.  **拥塞控制**：全局网络适配，防止发送方发送过载导致网络中间节点拥塞崩溃。

---

## 二、TCP报文段（Segment）结构
TCP报文封装在IP数据报中，分为**固定头部（20字节）**和**可选选项（最长40字节）**，因此TCP头部总长度最大为60字节。

| 字段 | 长度 | 核心作用与说明 |
| :--- | :--- | :--- |
| 源端口/目的端口 | 各16位 | 唯一标识通信两端的应用进程，端口范围0-65535；0-1023为熟知端口，1024-49151为注册端口，49152-65535为动态私有端口 |
| 序号（SEQ） | 32位 | 本报文段所携带数据的**第一个字节的编号**；SYN报文的序号为初始序号ISN，TCP字节流中每个字节都有唯一的32位循环序号 |
| 确认号（ACK） | 32位 | 期望接收的下一个字节的序号，**仅当ACK标志位为1时有效**；采用累计确认机制，代表该序号之前的所有字节已全部正确接收 |
| 数据偏移 | 4位 | 标识TCP头部长度，单位为4字节；最小值为5（对应20字节固定头部），最大值为15（对应60字节最大头部） |
| 保留位 | 6位 | 预留字段，必须全部置0 |
| 控制标志位（Flags） | 6位 | 核心控制位，每个位独立生效：<br>• **URG**：紧急指针有效，标识紧急数据<br>• **ACK**：确认号有效，除初始SYN包外，所有报文必须置1<br>• **PSH**：推送标志，要求接收方立即将数据上交应用层，不等待缓冲区填满<br>• **RST**：重置连接，强制关闭异常连接，拒绝非法报文<br>• **SYN**：同步序号，用于连接建立<br>• **FIN**：结束标志，用于关闭连接，标识本方无数据再发送 |
| 窗口大小 | 16位 | 接收方通告的接收窗口rwnd，标识本方当前接收缓冲区的剩余可用空间，是TCP流量控制的核心；最大值为65535字节，可通过窗口扩大选项扩展 |
| 校验和 | 16位 | 强制校验，覆盖TCP头部、数据段和伪首部（含源IP、目的IP、协议号、TCP长度），用于检测报文传输过程中的差错，校验失败的报文会被直接丢弃 |
| 紧急指针 | 16位 | URG=1时有效，指向紧急数据的最后一个字节的序号，紧急数据会被优先传输，无需等待缓冲区排队 |
| 选项 | 可变长度 | 4字节对齐，最长40字节，用于TCP功能扩展，核心常用选项见下文 |

### 核心TCP选项
1.  **MSS（最大报文段长度）**：TCP单报文段能承载的最大数据长度（不含TCP/IP头部），通常为以太网MTU(1500字节)-IP头(20字节)-TCP头(20字节)=1460字节，连接建立时协商，避免IP层分片。
2.  **窗口扩大因子（Window Scale）**：RFC 1323定义，解决16位窗口最大65535字节的限制，将窗口大小左移扩大因子位（最大14位），最大可支持1GB的窗口，适配高带宽长距离网络。
3.  **SACK（选择确认）**：RFC 2018定义，弥补累计确认的缺陷，接收方可告知发送方已收到的不连续字节块，发送方仅重传真正丢失的报文段，大幅提升重传效率；D-SACK（重复SACK）扩展可告知发送方重复接收的报文段，优化乱序/丢包判断。
4.  **时间戳（Timestamps）**：RFC 1323定义，两个核心作用：① 精准计算RTT，避免重传确认二义性；② PAWS机制，防止32位序号回绕导致的新旧报文混淆。
5.  **NOP**：无操作，用于填充选项，保证4字节对齐。

---

## 三、TCP连接管理
TCP连接的唯一标识是**四元组（源IP、源端口、目的IP、目的端口）**，完整生命周期分为**连接建立、数据传输、连接释放**三个阶段，基于有限状态机实现。

### 3.1 连接建立：三次握手
默认客户端为主动打开方，服务端为被动打开方，核心目标是双向同步初始序号ISN，验证双方收发能力正常，避免无效连接。

1.  **第一次握手**：客户端发送SYN报文（SYN=1，ACK=0，seq=ISN(c)），客户端进入`SYN_SENT`状态。
    作用：向服务端发起连接请求，同步客户端的初始序号。
2.  **第二次握手**：服务端收到SYN报文后，回复SYN+ACK报文（SYN=1，ACK=1，ack=ISN(c)+1，seq=ISN(s)），服务端进入`SYN_RCVD`状态。
    作用：确认客户端的连接请求，同时同步服务端的初始序号。
3.  **第三次握手**：客户端收到SYN+ACK报文后，回复ACK报文（ACK=1，ack=ISN(s)+1，seq=ISN(c)+1），客户端进入`ESTABLISHED`状态；服务端收到该ACK后，也进入`ESTABLISHED`状态。
    作用：确认服务端的初始序号，连接正式建立，可开始双向数据传输。

#### 高频核心问题：为什么是三次握手，不是两次？
1.  **防止失效的连接请求导致资源浪费**：若客户端发送的SYN报文在网络中滞留，超时后重发SYN并建立连接，后续滞留的SYN到达服务端，两次握手会让服务端直接建立连接，等待客户端数据，浪费服务端资源；三次握手可通过客户端的最终确认，过滤无效SYN。
2.  **确保双向收发能力正常，同步双方ISN**：TCP是全双工协议，需要双方都确认对方的发送/接收能力正常，且双向的初始序号都得到对方确认。两次握手仅能完成客户端到服务端的单向序号同步和能力验证，无法确认服务端到客户端的发送能力和序号有效性。

### 3.2 连接释放：四次挥手
TCP全双工的特性决定了双方的发送通道需要独立关闭，FIN报文仅能关闭本方的发送方向，因此需要四次交互完成双向关闭。默认客户端为主动关闭方，服务端为被动关闭方。

1.  **第一次挥手**：客户端发送FIN报文（FIN=1，ACK=1，seq=u），客户端进入`FIN_WAIT_1`状态。
    作用：告知服务端，客户端已无数据发送，请求关闭客户端到服务端的发送通道。
2.  **第二次挥手**：服务端收到FIN后，回复ACK报文（ACK=1，ack=u+1，seq=v），服务端进入`CLOSE_WAIT`状态；客户端收到该ACK后，进入`FIN_WAIT_2`状态。
    作用：确认客户端的关闭请求，告知客户端已收到关闭指令，但服务端可能还有数据未发送完成，需等待数据传输完毕再关闭。此时客户端→服务端的发送通道关闭，服务端→客户端的通道仍正常，进入半关闭状态。
3.  **第三次挥手**：服务端数据传输完成后，发送FIN报文（FIN=1，ACK=1，seq=w，ack=u+1），服务端进入`LAST_ACK`状态。
    作用：告知客户端，服务端已无数据发送，请求关闭服务端到客户端的发送通道。
4.  **第四次挥手**：客户端收到FIN后，回复ACK报文（ACK=1，ack=w+1，seq=u+1），客户端进入`TIME_WAIT`状态；服务端收到该ACK后，立即进入`CLOSED`状态。客户端等待**2MSL（最长报文段寿命）**后，无重传报文到达，也进入`CLOSED`状态，连接完全释放。

#### 高频核心问题
1.  **为什么是四次挥手，不是三次？**
    全双工模式下，被动关闭方收到FIN时，可能还有未传输完成的数据，无法将ACK确认和FIN关闭报文合并发送，必须先回复ACK确认关闭请求，待数据传输完成后，再发送FIN关闭本方通道，因此需要四次交互。而三次握手时，服务端无数据传输，可将SYN和ACK合并发送。

2.  **TIME_WAIT状态的作用，为什么要等待2MSL？**
    MSL是IP报文在网络中的最长存活时间，RFC建议为2分钟，实际系统通常设置为30s-2分钟。
    - 确保最后一个ACK报文能被对方接收：若服务端未收到第四次挥手的ACK，会重传FIN报文，TIME_WAIT状态可让客户端接收重传的FIN并重新发送ACK，避免服务端一直处于`LAST_ACK`状态无法关闭。
    - 防止本次连接的滞留报文污染下一个同四元组的连接：2MSL的时间足以让本次连接的所有报文从网络中彻底消失，避免旧连接的报文被新连接误接收，导致序号混淆和数据错乱。

---

## 四、TCP可靠传输核心机制
TCP的可靠传输，本质是通过**序号与确认机制**做基础，**超时重传、快速重传**做兜底，**SACK**做优化，最终实现字节流的有序、无差错交付。

### 4.1 序号与累计确认
- TCP为字节流中的每个字节分配唯一的32位序号，报文段的seq为该段第一个数据字节的序号。
- 接收方通过ACK报文的确认号，告知发送方已成功接收的最后一个字节的序号+1，代表该确认号之前的所有字节已全部正确接收，这就是**累计确认**。
- 累计确认的优势是实现简单，抗ACK丢包能力强；缺陷是无法告知发送方中间不连续的已接收数据，丢包时会导致不必要的重传，由SACK选项弥补。

### 4.2 超时重传与RTO计算
TCP发送一个报文段后，会启动重传定时器，若在**RTO（重传超时时间）**内未收到对应的ACK，就会重传该报文段。
1.  **RTO计算标准（RFC 6298）**：
    RTO基于RTT（报文往返时间）动态计算，避免固定超时时间导致的性能问题：
    - 平滑RTT：`SRTT = (1-α)×SRTT + α×RTT采样值`，α默认取1/8
    - RTT偏差：`RTTVAR = (1-β)×RTTVAR + β×|SRTT - RTT采样值|`，β默认取1/4
    - 最终RTO：`RTO = SRTT + 4×RTTVAR`，系统通常设置最小RTO为1s，最大为60s
2.  **Karn算法**：重传的报文段的RTT采样值不参与SRTT计算，解决“确认二义性”问题——无法判断收到的ACK是原报文的响应，还是重传报文的响应，避免RTO计算失真。
3.  **超时处理**：发生RTO超时后，TCP判断网络发生严重拥塞，会执行：慢启动阈值ssthresh置为当前cwnd的1/2，cwnd重置为初始值，重新进入慢启动阶段，同时执行指数退避，下一次超时的RTO翻倍。

### 4.3 快速重传（Fast Retransmit）
RFC 5681定义，无需等待RTO超时，当发送方连续收到**3个重复的ACK**时，立即重传对应的丢失报文段，大幅降低丢包后的传输延迟。
- 触发逻辑：发送方发送1、2、3、4、5号报文，2号报文丢失，接收方收到1号后回复ack=2，后续收到3、4、5号报文时，仍持续回复ack=2，形成3个重复ACK。
- 核心优势：避免等待超时时间，将丢包重传的延迟从秒级降到毫秒级，提升传输效率。

---

## 五、TCP流量控制
流量控制是**端到端的速率匹配机制**，核心解决“发送方发送过快，接收方缓冲区溢出导致丢包”的问题，基于滑动窗口协议实现。

### 5.1 滑动窗口核心原理
- 接收方在每个ACK报文的窗口字段中，通告本方当前的接收窗口`rwnd`（接收缓冲区剩余可用空间）。
- 发送方的发送窗口上限为`swnd = min(拥塞窗口cwnd, 接收窗口rwnd)`，确保发送的数据不会超过接收方的处理能力。
- 发送窗口内的字节分为4类：① 已发送并收到ACK；② 已发送未收到ACK；③ 未发送但允许发送；④ 未发送且不允许发送。收到新的ACK后，发送窗口向右滑动，将新的字节纳入允许发送范围。

### 5.2 关键补充机制
1.  **持续计时器（Persist Timer）**
    解决零窗口死锁问题：若接收方通告rwnd=0，发送方停止发送；若后续接收方更新rwnd>0的ACK报文丢失，发送方会一直等待，形成死锁。
    解决方案：发送方收到零窗口通知后，启动持续计时器，超时后发送1字节的窗口探测报文，接收方回复当前窗口大小；若窗口仍为0，重置计时器继续探测，直到窗口恢复非零。

2.  **糊涂窗口综合征（Silly Window Syndrome）**
    问题场景：接收方缓冲区满，应用程序每次仅读取1字节，接收方通告rwnd=1，发送方就发送1字节的报文段，导致TCP头部20字节+数据1字节，网络效率极低。
    解决方案：
    - 接收方策略：不通告小于MSS或缓冲区一半的窗口，仅当可用空间达到阈值时，才通告非零窗口。
    - 发送方策略：通过Nagle算法避免发送小报文段。

3.  **Nagle算法（RFC 896）**
    解决大量小报文段导致的网络带宽浪费问题，核心规则：
    - 若发送窗口内的数据长度≥MSS，立即发送；
    - 若当前没有已发送未确认的报文段，立即发送；
    - 否则，将数据放入缓冲区，直到收到ACK或缓冲区数据达到MSS，再统一发送。
    注意：Nagle算法与延迟ACK配合时，可能导致交互式应用（SSH、Telnet）出现额外延迟，可通过`TCP_NODELAY`选项关闭。

4.  **延迟ACK（Delayed ACK）**
    减少ACK报文的数量，降低网络开销，核心规则：
    - 不对每个报文段立即回复ACK，延迟最大200ms（Linux默认40ms），若延迟期间有数据要发送，将ACK与数据捎带发送；
    - 最多每2个连续的报文段，必须回复一个ACK。

---

## 六、TCP拥塞控制
拥塞控制是**全局网络适配机制**，核心解决“发送方发送过快，导致网络中间路由器过载、缓存溢出、丢包”的问题，避免网络拥塞崩溃。核心标准为RFC 5681，后续演进了多个优化算法。

TCP发送方维护一个**拥塞窗口cwnd**，代表在未收到ACK的情况下，最多可发送的字节数，最终发送窗口`swnd = min(cwnd, rwnd)`，拥塞控制的核心就是根据网络拥塞状态，动态调整cwnd的大小。

### 6.1 传统拥塞控制四大核心阶段（Reno算法）
1.  **慢启动（Slow Start）**
    - 连接建立初始，cwnd设置为较小的初始值（RFC 5681建议10个MSS），每收到一个ACK，cwnd增加1个MSS，每经过一个RTT，cwnd指数翻倍。
    - 核心目标：快速探测网络可用带宽，“慢启动”指初始值小，而非增长速度慢。
    - 退出条件：当cwnd≥慢启动阈值ssthresh时，进入拥塞避免阶段。

2.  **拥塞避免（Congestion Avoidance）**
    - cwnd从指数增长转为线性增长，每经过一个完整的RTT，cwnd仅增加1个MSS，无论收到多少个ACK。
    - 核心目标：缓慢逼近网络最大带宽，避免快速增长导致网络拥塞。

3.  **快速重传**
    收到3个重复ACK时，立即重传丢失的报文段，无需等待RTO超时，判断网络为轻微拥塞，不进入慢启动，直接进入快速恢复阶段。

4.  **快速恢复（Fast Recovery）**
    - 触发快速重传后，将ssthresh置为当前cwnd的1/2，cwnd置为ssthresh + 3×MSS；
    - 每收到一个重复ACK，cwnd增加1个MSS，继续发送允许的报文段；
    - 收到确认丢失报文的新ACK后，将cwnd重置为ssthresh，进入拥塞避免阶段。
    - 核心目标：避免轻微拥塞时直接进入慢启动导致的带宽利用率骤降。

> 若发生RTO超时，判断为网络严重拥塞，执行：ssthresh = cwnd/2，cwnd重置为初始值，重新进入慢启动。

### 6.2 主流拥塞控制算法演进
| 算法 | 核心特点 | 适用场景 |
| :--- | :--- | :--- |
| Reno | 传统标准算法，基于丢包判断拥塞，四大阶段实现 | 传统低带宽、低延迟网络 |
| NewReno | 优化Reno，支持一个窗口内多个丢包的处理，减少不必要的慢启动 | 通用网络，替代Reno |
| CUBIC | Linux默认算法，基于三次函数的增长曲线，高带宽下增长更平稳，抗震荡能力强 | 高带宽延迟积的有线网络、数据中心 |
| BBR | Google研发，基于瓶颈带宽和最小RTT的拥塞控制，不依赖丢包判断拥塞，最大化带宽利用率，最小化延迟 | 高带宽长距离网络、无线网络（抗随机丢包）、CDN/云服务 |

---

## 七、TCP核心扩展与优化
1.  **TCP Fast Open（TFO，RFC 7413）**：允许在三次握手的SYN报文中携带应用数据，实现0RTT数据传输，大幅缩短HTTP等短连接的建立延迟。
2.  **MP-TCP（MultiPath TCP，RFC 6824）**：支持一个TCP连接同时使用多个网络接口（如WiFi+5G），实现带宽叠加、网络无缝切换，提升传输可靠性和吞吐量。
3.  **TCP头部压缩（TCP HC）**：针对无线网络优化，压缩TCP/IP头部，降低小包传输的开销，提升无线链路的带宽利用率。

---

## 八、TCP vs UDP 核心对比
| 特性 | TCP | UDP |
| :--- | :--- | :--- |
| 连接性 | 面向连接，需三次握手建立、四次挥手释放 | 无连接，无需预建立，直接发送报文 |
| 可靠性 | 可靠，保证数据无丢失、无重复、按序到达 | 不可靠，不保证交付、不保证顺序，无重传 |
| 传输模式 | 面向字节流，无报文边界，自动分片重组 | 面向数据报，有严格边界，不合并不拆分 |
| 控制机制 | 流量控制、拥塞控制、超时重传、SACK等全套机制 | 仅支持基础校验和，所有可靠性逻辑由上层应用实现 |
| 头部开销 | 固定20字节，最大60字节 | 固定8字节，开销极低 |
| 双工性 | 全双工 | 全双工 |
| 核心场景 | HTTP/HTTPS、FTP、SMTP、SSH、WebSocket等需可靠传输的场景 | 直播、音视频通话、实时游戏、DNS、NTP、广播多播等低延迟优先场景 |

---

## 九、TCP常见问题与排查方向
1.  **三次握手失败**：防火墙拦截、服务端未监听对应端口、SYN半连接队列溢出（SYN洪水攻击）。
2.  **CLOSE_WAIT状态过多**：应用层代码缺陷，被动关闭方未调用`close()`释放文件描述符。
3.  **TIME_WAIT状态过多**：短连接场景下主动关闭方频繁创建/释放连接，占用端口资源，可通过调整`tcp_tw_reuse`等内核参数优化。
4.  **吞吐量低**：MSS设置过小、未开启窗口扩大选项、拥塞控制算法不匹配、链路丢包导致频繁重传。
5.  **传输延迟高**：Nagle算法与延迟ACK叠加、RTT过大、频繁重传、拥塞控制降速。

---

## 核心参考RFC文档
- RFC 793：TCP核心协议规范
- RFC 5681：TCP拥塞控制标准
- RFC 6298：TCP RTO计算标准
- RFC 2018：TCP SACK选择确认
- RFC 1323：TCP高带宽扩展（窗口扩大、时间戳）
- RFC 8312：BBR拥塞控制算法
- RFC 7413：TCP Fast Open快速打开


