一、特点:
(一)面向连接
在进行数据传输之前,TCP 需要在发送方和接收方之间建立一条逻辑连接。这一过程类似于打电话,双方在通话前需要先拨号建立连接。建立连接的过程通过三次握手来完成,确保通信双方都做好了数据传输的准备。连接建立后,数据按照顺序有序传输,直到通信结束,通过四次挥手关闭连接。
(二)可靠性
- 校验和:TCP 在发送数据时,会对数据部分计算校验和,并将校验和放入 TCP 首部。接收方在接收到数据后,会重新计算校验和并与接收到的校验和进行对比。如果两者不一致,说明数据在传输过程中出现了错误,接收方会要求发送方重新发送数据。
- 确认机制:接收方收到数据后,会向发送方发送确认(ACK)消息,告知发送方数据已成功接收。发送方在发送数据后,会启动一个定时器,如果在定时器超时之前没有收到 ACK,就会认为数据传输失败,并重发数据。
- 重传机制:除了超时重传,TCP 还采用了快速重传机制。当接收方连续收到三个相同的 ACK 时,就会认为中间的数据段丢失,发送方会立即重传丢失的数据段,而不需要等待定时器超时,大大提高了数据传输的效率。
- 排序与重复数据处理:TCP 会对接收的数据按照序号进行排序,确保数据按顺序交付给应用层。同时,对于重复接收的数据,TCP 会进行丢弃处理,保证应用层不会接收到重复的数据。
(三)字节流服务
TCP 将数据视为无结构的字节流进行传输,应用层可以按照任意大小的数据块进行读写,而不必担心数据的边界问题。TCP 会在发送方将数据分割成合适大小的段进行传输,并在接收方将这些段重新组装成完整的字节流交付给应用层。
二、连接管理机制
(一)连接建立(三次握手)
- 第一次握手:客户端向服务器发送一个带有 SYN(同步序列号)标志位的 TCP 报文段,该报文段中包含客户端随机生成的初始序列号(Sequence Number,简称 SEQ),假设为 x。此时客户端进入 SYN_SENT 状态,等待服务器的响应。
- 第二次握手:服务器接收到客户端的 SYN 报文段后,向客户端发送一个 SYN + ACK 报文段。该报文段中的 SYN 标志位表示服务器同意建立连接,ACK 标志位用于确认收到客户端的 SYN。服务器也会生成一个自己的初始序列号,假设为 y,并将客户端的序列号 x 加 1 作为确认号(Acknowledgment Number,简称 ACK),即 ACK = x + 1。此时服务器进入 SYN_RCVD 状态。
- 第三次握手:客户端接收到服务器的 SYN + ACK 报文段后,向服务器发送一个 ACK 报文段。该报文段的 ACK 标志位有效,确认号为服务器的序列号 y 加 1,即 ACK = y + 1,序列号为客户端在第一次握手中发送的序列号 x 加 1,即 SEQ = x + 1。此时客户端和服务器都进入 ESTABLISHED 状态,连接建立成功。
(二)数据传输
连接建立后,客户端和服务器就可以进行数据传输了。发送方将应用层的数据分割成 TCP 段,每个 TCP 段包含 TCP 首部和数据部分。TCP 首部中包含源端口、目的端口、序列号、确认号、标志位等信息。发送方按照序列号顺序发送数据段,接收方接收数据段后,根据序列号进行排序,并向发送方发送 ACK 确认。如果发送方在规定时间内没有收到 ACK,就会重发数据段。
(三)连接关闭(四次挥手)
- 第一次挥手:客户端向服务器发送一个 FIN(结束标志位)标志位有效的 TCP 报文段,表示客户端不再发送数据,但仍可以接收数据。此时客户端进入 FIN_WAIT_1 状态。
- 第二次挥手:服务器接收到客户端的 FIN 报文段后,向客户端发送一个 ACK 报文段,确认收到客户端的 FIN,此时服务器进入 CLOSE_WAIT 状态。客户端收到 ACK 后,进入 FIN_WAIT_2 状态。
- 第三次挥手:服务器在处理完剩余的数据后,向客户端发送一个 FIN 标志位有效的 TCP 报文段,表示服务器也不再发送数据。此时服务器进入 LAST_ACK 状态。
- 第四次挥手:客户端接收到服务器的 FIN 报文段后,向服务器发送一个 ACK 报文段,确认收到服务器的 FIN。此时客户端进入 TIME_WAIT 状态,经过一段时间(通常为 2 倍的最大段生存期,即 2MSL)后,客户端进入 CLOSED 状态,彻底关闭连接。服务器在收到客户端的 ACK 后,立即进入 CLOSED 状态。
看到这,有的读友可能会想到,建立连接时为什么需要3次握手?请求+响应两次握手不行吗?接下来就一同看看两次握手会出现什么问题。
如上图左边场景,客户端选择一个初始序列号x,发送连接请求报文 req_conn(x)
给服务器,服务器接收到连接请求后,发送确认连接报文acc_conn(x)
,并且进入已连接状态。而在客户端超时定时器到时的时候,客户端没有接收到服务器的确认报文。此时,客户端重发连接请求req_conn(x)
,一会儿,第一次的acc_conn到达客户端处,连接建立,进行数据通信,然后通信结束。结束后,重发的req_conn(x)
到达了服务器,服务器端会认为又建立了一个新连接(因为它不记得之前已经处理过 ),又会发送acc_conn(x)
,而客户端会忽略这个确认(因为已经建立连接 )。这就导致服务器端维护了多余的、不完整的连接(半连接 )。服务器端资源被无效占用,连接管理也出现混乱。
由此可看出,2次握手导致半连接问题
再看右侧场景,建立连接过程中,由于某种原因,服务器端ack迟迟不到,致使客户端超时重发req_conn(x)
,此后,延迟的ack
到达客户端,连接建立。客户端向服务器发送数据,而又由于某种原因,data
的ack
迟迟不到,客户端超时重发数据data.重发后延迟的ack到达客户端,通信结束,连接关闭。此后,重发的req_conn
及data
到达服务器,使得老的数据被当作新的数据接收。这将导致数据错乱,业务逻辑错误
综上,二次握手存在的问题如下:
问题类型 | 根本原因 | 后果 | 三次握手解决方案 |
半连接 | 缺乏客户端最终确认 | 服务器资源浪费,通信中断 | 通过第三次ACK验证连接有效性 |
旧数据误认 | 无法区分历史连接与新连接 | 数据错乱,业务逻辑错误 | 动态ISN + 序列号严格同步 |
双向能力未验证 | 仅验证单向可达性 | 单向通信风险(如服务器→客户端不可达) | 三次交互确认双向链路 |
因此,必须采用三次握手。
三、可靠数据传输
1. 确认应答(ACK)机制
- 序列号与确认号:每个数据包携带32位序列号(SEQ)标识字节流起始位置,接收方通过确认号(ACK=SEQ+数据长度)反馈已接收的数据范围。例如,发送方发送SEQ=1000、长度500的数据,接收方返回ACK=1500
- ACK标志位:TCP头部中ACK标志位为1时,表示该报文为确认报文,此时确认号字段生效。普通数据报文ACK标志位为0 。
- 累积确认:接收方仅需确认连续接收的最高序列号,简化ACK处理。例如,若接收方已收到SEQ=1000-2000的数据,即使中间有乱序包(如SEQ=2500),仍返回ACK=2001,触发发送方选择性重传 。
2. 超时重传与动态RTO
- 重传触发条件:发送方在动态计算的重传超时时间(RTO)内未收到ACK,触发数据包重传。RTO基于往返时间(RTT)自适应调整,计算公式为:
SRTT = (1-α) * SRTT + α * RTT_sample
DevRTT = (1-β) * DevRTT + β * |RTT_sample - SRTT|
RTO = SRTT + 4 * DevRTT
其中,α=0.125,β=0.25(经验值)。
- 超时加倍策略:首次超时后,RTO逐次加倍,避免网络拥塞恶化 。
- 接收缓冲区去重:接收方通过缓冲区存储已接收数据并按序重组,丢弃重复数据包(如因重传导致的冗余包) 。
3. 滑动窗口与高效传输
- 窗口动态调整:发送窗口大小(SWND)取接收窗口(RWND)与拥塞窗口(CWND)的最小值,确保发送速率匹配接收方处理能力和网络状态。
- 批量发送与累积ACK:发送方可在窗口内连续发送多个数据包,接收方通过累积ACK减少确认次数。例如,发送窗口为4时,发送SEQ=1-4的数据包,接收方返回ACK=5确认全部接收。
- 选择性确认(SACK):通过TCP选项字段标记非连续接收的数据块范围,发送方仅重传丢失的包(如接收方反馈SACK=3000-3500,发送方重传缺失的2500-3000) 。
- D-SACK:接收方通过SACK反馈重复接收的数据块,帮助发送方区分ACK丢失或网络延迟,优化重传策略 。
4. 拥塞控制
1. 慢开始(Slow Start):在连接建立初期,发送方将拥塞窗口(Congestion Window,简称 cwnd)初始化为一个最大段大小(MSS),然后每收到一个 ACK,就将拥塞窗口增加一个 MSS。这样,拥塞窗口呈指数增长,快速探测网络的承载能力。
2. 拥塞避免(Congestion Avoidance):当拥塞窗口增长到慢开始门限(ssthresh)时,进入拥塞避免阶段。在这个阶段,发送方每收到一个 ACK,就将拥塞窗口增加 1/cwnd 个 MSS,使拥塞窗口线性增长,避免网络拥塞。
3. 快重传(Fast Retransmit):当接收方连续收到三个相同的 ACK 时,发送方会立即重传丢失的数据段,而不需要等待定时器超时。这可以快速恢复丢失的数据,减少数据传输的延迟。
4. 快恢复(Fast Recovery):在快重传之后,发送方将慢开始门限设置为当前拥塞窗口的一半,然后将拥塞窗口设置为慢开始门限加上三个重复 ACK 所确认的数据量,接着进入拥塞避免阶段,而不是重新进入慢开始阶段。这样可以更快地恢复数据传输,提高网络的利用率。
四、流量控制
1. 滑动窗口工作机制
- 接收窗口(RWND):接收方通过ACK报文中的窗口字段告知剩余缓冲区大小。例如,RWND=8000表示当前可接收8000字节数据 27。
- 零窗口探测:若接收方缓冲区满(RWND=0),发送方启动持续计时器,定期发送1字节探测包,检测窗口恢复状态 27。
- 窗口缩放选项:通过TCP选项扩展窗口字段位数(从16位至30位),支持高带宽网络的大窗口传输。
2. 流量控制的关键问题与解决
- 糊涂窗口综合征(SWS)
-
- 发送端SWS:Nagle算法解决小数据包问题,规则如下:
if 有新数据待发送: if 窗口大小 ≥ MSS 且 数据量 ≥ MSS: 立即发送 elif 有未确认数据: 缓存数据等待ACK else: 立即发送
此算法在高延迟场景可能导致小数据等待,可通过TCP_NODELAY
选项 禁用
-
- 接收端SWS:接收方在缓冲区不足时直接通告RWND=0,强制发送方暂停,待缓冲区清空后通过探测包恢复 。
3. 拥塞控制与流量控制的协同
- 拥塞窗口(CWND):根据网络拥塞状态动态调整,通过慢启动(指数增长)和拥塞避免(线性增长)平衡带宽利用率 。
- 全局平衡:最终发送速率受
SWND = min(RWND, CWND)
限制,同时避免接收方溢出和网络拥塞。
五、TCP报文格式
头部结构(20~60字节)
字段 | 长度 | 说明 |
源端口/目的端口 | 16位 | 标识应用程序(如HTTP=80) |
序列号(SEQ) | 32位 | 数据包首字节的全局位置 |
确认号(ACK) | 32位 | 期望接收的下一个字节序号(仅当ACK=1时有效) |
数据偏移 | 4位 | 首部长度(以4字节为单位,最大60字节) |
控制标志 | 9位 | SYN(连接请求)、ACK(确认)、FIN(终止)、RST(重置)、PSH(急迫推送) |
窗口大小 | 16位 | 接收方可用缓冲区大小(流量控制关键参数) |
校验和 | 16位 | 验证数据完整性 |
紧急指针 | 16位 | 标识紧急数据位置(仅当URG=1时有效) 。 |