一、TCP的定位与核心特性
TCP(Transmission Control Protocol,传输控制协议)是TCP/IP协议栈中传输层的核心协议,与UDP(用户数据报协议)共同承担端到端数据传输功能。其设计目标是在不可靠的IP网络上提供可靠、有序、面向连接的字节流服务,是互联网中绝大多数应用(如HTTP、FTP、SMTP等)的基础。
与UDP相比,TCP的核心特性差异如下:
- 面向连接:通信前需通过“三次握手”建立连接,结束后需“四次挥手”释放连接;UDP无连接。
- 可靠传输:通过序号、确认、重传等机制确保数据不丢失、不重复、按序到达;UDP不保证可靠性。
- 字节流服务:将应用层数据视为连续字节流,无消息边界;UDP保留消息边界。
- 流量控制与拥塞控制:通过滑动窗口避免接收方缓冲区溢出,通过拥塞算法避免网络拥塞;UDP无此类机制。
- 适用于场景:对可靠性要求高(如文件传输、网页加载);UDP适用于实时性要求高(如视频通话、游戏)。
二、TCP报文结构
TCP报文由首部和数据两部分组成,首部最小20字节,最大60字节(含选项字段)。各字段含义如下:
字段 | 长度(字节) | 含义 |
---|---|---|
源端口/目的端口 | 2/2 | 标识发送端和接收端的应用进程(如HTTP默认80端口)。 |
序号(Sequence Number) | 4 | 本报文数据段第一个字节的序号(用于按序重组和去重)。 |
确认号(Acknowledgment Number) | 4 | 期望接收的下一字节序号(仅当ACK=1时有效,即确认已收到序号≤(确认号-1)的数据)。 |
数据偏移(Header Length) | 4位 | 表示TCP首部长度(以32位字为单位,最小值5(20字节),最大值15(60字节))。 |
保留位 | 6位 | 预留未来使用,目前需设为0。 |
控制位(Flags) | 6位 | 共6个标志位:URG(紧急指针有效)、ACK(确认号有效)、PSH(推数据至应用层)、RST(重置连接)、SYN(同步序号,建立连接)、FIN(终止连接)。 |
窗口大小(Window) | 2字节 | 接收窗口(rwnd),告知发送方可接收的字节数(流量控制核心字段)。 |
校验和(Checksum) | 2字节 | 用于检测报文段在传输中是否损坏(覆盖伪首部、TCP首部、数据)。 |
紧急指针(Urgent Pointer) | 2字节 | 当URG=1时有效,指示紧急数据在报文段中的偏移量(紧急数据优先处理)。 |
选项(Options) | 0-40字节 | 可选字段,如MSS(最大报文段长度)、SACK(选择确认)、Window Scale(窗口扩大因子)等。 |
三、TCP连接管理
TCP是“面向连接”的协议,连接管理包含建立连接(三次握手) 和释放连接(四次挥手) 两个过程,通过控制位(SYN、ACK、FIN)实现。
1. 三次握手(建立连接)
三次握手的目标是:① 确保双方收发能力正常;② 协商初始序号(ISN);③ 同步连接状态。流程如下:
-
第一次握手:客户端 → 服务器
发送SYN报文(SYN=1,ACK=0),携带客户端初始序号ISN_c(如x)。此时客户端进入SYN_SENT
状态。 -
第二次握手:服务器 → 客户端
服务器收到SYN后,回复SYN+ACK报文(SYN=1,ACK=1),携带服务器初始序号ISN_s(如y),并确认客户端序号(确认号=ISN_c+1=x+1)。此时服务器进入SYN_RCVD
状态。 -
第三次握手:客户端 → 服务器
客户端收到SYN+ACK后,发送ACK报文(ACK=1),确认服务器序号(确认号=ISN_s+1=y+1)。此时客户端进入ESTABLISHED
状态;服务器收到ACK后也进入ESTABLISHED
状态,连接建立。
为何需要三次握手?
- 防止“过期连接请求”干扰:若客户端的SYN报文因网络延迟到达服务器,服务器会误以为是新连接并回复SYN+ACK。若仅两次握手,服务器会直接建立连接并等待数据,但客户端已丢弃该过期请求,导致服务器资源浪费。三次握手通过客户端的最终ACK,确保双方确认“当前连接有效”。
用最简单的例子解释为什么需要三次握手:
A: 喂,能听见吗?
B: 能听见,你能听见我吗?
A: 能听见。
2. 四次挥手(释放连接)
TCP支持“半关闭”(一方关闭发送后仍可接收数据),因此释放连接需四次交互:
-
第一次挥手:客户端 → 服务器
客户端主动关闭,发送FIN报文(FIN=1,ACK=1),表示不再发送数据(但可接收),携带序号u(最后发送字节的序号+1)。客户端进入FIN_WAIT_1
状态。 -
第二次挥手:服务器 → 客户端
服务器收到FIN后,回复ACK报文(ACK=1),确认号=u+1,告知客户端“已收到关闭请求”。服务器进入CLOSE_WAIT
状态,客户端进入FIN_WAIT_2
状态(等待服务器剩余数据)。 -
第三次挥手:服务器 → 客户端
服务器发送完剩余数据后,发送FIN报文(FIN=1,ACK=1),携带序号v(服务器最后发送字节的序号+1),确认号=u+1(与第二次挥手一致)。服务器进入LAST_ACK
状态。 -
第四次挥手:客户端 → 服务器
客户端收到FIN后,回复ACK报文(ACK=1),确认号=v+1,客户端进入TIME_WAIT
状态;服务器收到ACK后进入CLOSED
状态。客户端等待2MSL(最大报文段寿命,通常为1-2分钟)后,也进入CLOSED
状态,释放连接。
四次挥手:
A:再见
B:收到
B:再见
A:收到
关键细节:
- 为何四次挥手? 第二次挥手(ACK)和第三次挥手(FIN)无法合并,因为服务器可能还有数据需发送(半关闭状态)。
- TIME_WAIT状态:持续2MSL(确保最后一个ACK被服务器收到;防止旧报文干扰新连接)。若服务器未收到ACK,会重发FIN,客户端需在TIME_WAIT内处理。
3. TCP状态机
连接管理的状态转换可通过状态机描述,核心状态包括:
- 客户端:
CLOSED
→SYN_SENT
→ESTABLISHED
→FIN_WAIT_1
→FIN_WAIT_2
→TIME_WAIT
→CLOSED
- 服务器:
CLOSED
→LISTEN
→SYN_RCVD
→ESTABLISHED
→CLOSE_WAIT
→LAST_ACK
→CLOSED
异常状态:RST
(重置连接,用于处理错误,如连接不存在时强制关闭)。
四、TCP可靠传输机制
TCP通过多重机制确保数据“可靠传输”(不丢失、不重复、按序到达),核心包括序号与确认、超时重传、快速重传与恢复、选择确认(SACK) 等。
1. 序号与确认机制
- 序号:每个字节数据分配唯一序号(初始为ISN,后续按字节递增)。例如,若ISN=100,发送50字节数据,序号为100-149,下一个序号为150。
- 确认号:采用“累计确认”,表示“已正确接收序号≤(确认号-1)的所有数据”,期望接收确认号对应的字节。例如,收到序号100-149的数据,确认号为150。
2. 超时重传
当发送方未在规定时间内收到确认,会重传该数据,关键是超时时间(RTO) 的计算:
- RTO需动态调整(基于RTT,往返时间):
- 样本RTT(SampleRTT):单次报文往返时间;
- 平滑RTT(SRTT):SRTT = (1-α)×SRTT + α×SampleRTT(α通常为0.125);
- RTT偏差(RTTVAR):RTTVAR = (1-β)×RTTVAR + β×|SampleRTT - SRTT|(β通常为0.25);
- 最终RTO = SRTT + 4×RTTVAR(确保97%的RTT落在RTO内)。
3. 快速重传与快速恢复
- 快速重传:当发送方收到3个重复确认(确认号相同),无需等待超时,立即重传未被确认的报文(推断该报文已丢失)。
- 快速恢复:重传后不执行慢启动(避免网络拥塞加剧),而是将拥塞窗口(cwnd)设为慢启动阈值(ssthresh),直接进入拥塞避免阶段。
4. 选择确认(SACK)
累计确认的缺陷:若中间报文丢失,后续报文即使到达也无法被单独确认。SACK通过选项字段告知发送方“已接收的非连续数据块”,发送方仅重传丢失部分。例如,接收方收到1-100、201-300,SACK会标记这两个区间,发送方仅重传101-200。
五、流量控制
流量控制用于防止发送方速率超过接收方处理能力,基于“滑动窗口机制”,通过接收窗口(rwnd)实现。
1. 滑动窗口原理
- 发送窗口:发送方可发送但未确认的数据范围,大小由接收窗口(rwnd)和拥塞窗口(cwnd)共同决定(发送窗口=min(rwnd, cwnd))。
- 接收窗口:接收方缓冲区剩余空间(rwnd = 接收缓冲区大小 - 已接收未读取数据量),通过TCP报文的“窗口大小”字段告知发送方。
窗口分为三部分:
- 已发送且确认:序号≤已确认序号;
- 已发送未确认:序号在已确认序号+1 至 发送窗口左沿-1;
- 未发送但可发送:序号在发送窗口左沿 至 发送窗口右沿-1;
- 不可发送:序号≥发送窗口右沿。
2. 窗口动态调整
- 接收方随缓冲区使用情况更新rwnd(若缓冲区满,rwnd=0);
- 发送方根据rwnd调整发送窗口:若rwnd=0,发送方停止发送,定期发送“零窗口探测报文”(1字节),接收方回复新的rwnd后恢复发送。
六、拥塞控制
拥塞控制用于防止发送方速率超过网络承载能力(避免网络拥塞导致丢包),核心是通过调整拥塞窗口(cwnd) 控制发送速率,涉及四大算法:慢启动、拥塞避免、快重传、快恢复。
1. 核心参数
- 拥塞窗口(cwnd):发送方根据网络拥塞状态动态调整的窗口(初始为1MSS);
- 慢启动阈值(ssthresh):cwnd增长的临界点(初始为较大值,如65535字节)。
2. 算法流程
- 慢启动:cwnd从1MSS开始,每收到一个确认(或每经过一个RTT),cwnd翻倍(指数增长),直到cwnd达到ssthresh,进入拥塞避免阶段。
- 拥塞避免:cwnd每经过一个RTT增加1MSS(线性增长),降低拥塞风险。
- 拥塞处理:
- 若超时重传(严重拥塞):ssthresh = cwnd/2,cwnd重置为1MSS,重新慢启动;
- 若收到3个重复确认(轻度拥塞):触发快重传,ssthresh = cwnd/2,cwnd = ssthresh,进入拥塞避免(快恢复)。
七、其他重要特性
- 面向字节流:TCP将应用数据视为连续字节流,无消息边界,应用层需自行处理数据分割(如通过长度字段或分隔符)。
- 最大报文段长度(MSS):TCP报文段最大数据部分长度(MSS = MTU - IP首部长度 - TCP首部长度,以太网中通常为1460字节),在三次握手的SYN报文中协商。
- Nagle算法:减少小报文数量(如连续发送多个1字节数据),规则是:未确认数据时,仅当数据达MSS或收到确认,才发送。可通过
TCP_NODELAY
选项关闭(适用于实时性场景,如SSH)。 - 延迟确认:接收方不立即回复ACK,而是延迟500ms(或在发送数据时一并确认),减少ACK数量。若500ms内收到新数据,会合并确认。
八、常见问题与优化
-
粘包问题:TCP字节流无边界,导致应用层收到的数据可能合并(粘包)或拆分。解决方法:
- 固定长度:每个消息固定大小;
- 分隔符:用特殊字符(如
\r\n
)分隔消息; - 长度前缀:消息头部包含长度字段。
-
TIME_WAIT积累:高并发场景下,大量
TIME_WAIT
状态连接会占用端口。优化方案:- 开启
SO_REUSEADDR
:允许端口快速复用; - 缩短TIME_WAIT时长(如调整
net.ipv4.tcp_fin_timeout
)。
- 开启
-
拥塞控制优化:传统算法(如Reno)在高带宽延迟网络(如卫星链路)效率低,现代算法如BBR(基于带宽和延迟)、CUBIC(基于三次函数增长)可提升性能。
TCP是互联网可靠传输的基石,通过三次握手建立连接、四次挥手释放连接,结合序号确认、超时重传、SACK等机制确保可靠性,通过滑动窗口实现流量控制,通过慢启动、拥塞避免等算法实现拥塞控制。理解TCP的核心机制,对网络编程、性能优化及问题排查至关重要。其设计兼顾了可靠性与效率,是计算机网络中最复杂且应用最广泛的协议之一。