ZeroOne AI
← 返回文章列表

深入理解TCP协议(二):TCP可靠传输与高效通信机制详解

👁 7
分类:通讯协议

本文深入TCP的七大核心工作机制:确认应答、超时重传、滑动窗口、流量控制、拥塞控制、延迟应答与捎带应答。详解丢包的本质与去重、超时时间如何确定、滑动窗口的发送流程与空间复用、快速重传、零窗口探测、窗口扩大因子、慢启动与拥塞避免,以及各机制如何协同实现TCP既可靠又高效的传输,为理解三次握手与四次挥手打下基础。

前言:从"字段"到"机制"

在上一篇文章中,我们认识了 TCP 报头中的各个字段:序号、确认序号、窗口大小、标志位等。但仅仅知道字段含义,并不等于理解了 TCP 的工作方式。例如:

这些问题不是某一个字段单独完成的,而是由 TCP 的一系列机制协同完成。本文从 TCP 的工作机制出发,介绍七大核心机制:

机制要解决的问题
确认应答机制确认数据是否被接收
超时重传机制数据丢失后重新发送
滑动窗口机制允许连续发送多个数据,提高传输效率
流量控制机制防止发送速度超过接收方的处理能力
拥塞控制机制防止发送速度超过网络的承载能力
延迟应答机制减少 ACK 报文数量,降低网络开销
捎带应答机制将 ACK 与数据合并发送,提高网络利用率

这些机制相互配合,共同构成了 TCP 可靠且高效的通信方式。接下来我们从最基础的确认应答机制开始。

一、确认应答机制

发送端发送一个 TCP 报文,接收端收到后,会给发送端回复一个 ACK 报文(ACK 报文本质也是一个 TCP 报文,只是 ACK 标志位置为 1,告诉对端"我收到了你发送过来的数据",同时表明确认序号有效)。

TCP 将发送缓冲区中的每个字节都进行了编号,即序列号。对于发送出去的 TCP 报文,它的序号为要发送数据的起始序号。当主机 B 收到主机 A 的报文后,返回的 ACK 报文其确认序号 = 接收报文的序号 + 接收报文的数据长度。

再次明确确认序号的定义:接收方已经收到指定序号之前的所有数据,下一次希望接收的数据序号

确认应答的本质

一句话总结:单独的确认应答机制不能保证数据最终一定到达,但可以保证确认序号之前的数据一定到达

二、超时重传机制

发送方没有收到应答时,无法保证报文是否被接收,因此需要重新发送——这就是超时重传机制

2.1 理解丢包的本质

发送方没收到应答,只存在两种丢包情况:

情况说明发送方的处理
数据报文丢失发送方发送的 TCP 报文在网络传输过程中丢失重新发送该报文
ACK 报文丢失接收方已收到报文并回复 ACK,但 ACK 在传输中丢失重新发送该报文(此时涉及去重)

对于第二种情况,接收方不会重复接收已收到的报文,它是通过确认序号来判断的:接收方会维护已收到的确认序号,当发送方重传的报文序号落在已确认范围内时,直接丢弃,从而完成去重

2.2 超时时间如何确定

网络环境不断变化,报文往返时间(RTT)并不固定,因此超时时间不能设成固定值:

因此 TCP 根据测量得到的 RTT 动态计算合理的超时时间。发生超时重传后,TCP 还会逐渐增加后续的等待时间(第一次超时等待、第二次等待更久、第三次继续延长……),避免网络异常或拥塞时频繁重传、进一步占用网络资源。但当重传累计到一定次数后,TCP 会认为网络或对端主机出现异常,不再重传,而是强制关闭连接。具体的超时计算与重传次数限制由 TCP 实现决定。

三、滑动窗口机制

如果每发送一个报文都必须等 ACK 到达才能发送下一个,通信效率会非常低——发送方会消耗大量时间等待 ACK,尤其是在高延迟网络下,即使双方处理能力很强也无法充分利用带宽。

TCP 的答案是:允许发送方在没有收到 ACK 的情况下连续发送多个报文,通过后续收到的 ACK 确认哪些数据已被接收。管理这部分"已发送但未确认数据"的机制,就是滑动窗口机制

3.1 深入理解 send/write 与发送缓冲区

每个 TCP Socket 都有一个发送缓冲区。send/write 的本质是把应用层数据拷贝到内核级发送缓冲区,而不是直接发送到网络。发送缓冲区中的数据什么时候发、一次发多少、丢失怎么办,全由操作系统基于 TCP 协议决定。

可以把发送缓冲区想象成 char buffer[N],划分为三个部分:

区域状态
已发送且已确认数据使命完成,缓冲区空间可被释放复用
已发送但未确认(滑动窗口区域)等待 ACK,窗口左边界所在
尚未发送等待进入窗口的数据

3.2 理解滑动窗口

窗口可以理解为一端连续的子数组:发送方要发送 1~10 的数据,假设发送窗口大小为 4,则一次最多发送 1、2、3、4,即发送的数据量不超过窗口大小。

在 TCP 中,滑动窗口的本质就是发送缓冲区中"可以直接发送、暂时不需要确认"的一部分数据。之所以叫"滑动",是因为随着发送方不断收到 ACK,已发送未确认的数据逐渐变成已发送已确认,窗口左边界不断右移,右边界也随之右移,整个窗口不断向前滑动。

滑动窗口的意义:允许 TCP 在等待 ACK 的过程中继续发送一定范围内的数据,减少等待时间,提高网络通信效率

3.3 滑动窗口下的发送流程与丢包处理

假设窗口最大为 4000 字节,发送方可以一次性发送 11000、10012000、20013000、30014000 四段数据而无需等待 ACK;收到第一个 ACK 后窗口右滑,继续发送 4001~5000,依此类推。

如果数据丢失怎么办?滑动窗口不会跳过未收到的报文,丢包可分为三类:

(1)最左侧丢失

(2)中间丢失、(3)最右侧丢失:都可以转化为最左侧丢失的情况——中间报文丢失时,窗口左边界会移动到丢失报文的位置;最右侧丢失同理。

3.4 发送缓冲区的空间复用

随着报文不断发送,已发送且已确认的数据不再需要,对应缓冲区空间可以被释放并重新利用,存放后续要发送的新数据。因此可以把发送缓冲区抽象成环形队列来理解:滑动窗口只是其中当前允许发送的一部分区域。

3.5 快速重传机制

滑动窗口带来一个新问题:如果某个报文丢失,接收方返回的 ACK 确认序号只能是最小的那个丢失报文,窗口左边界无法滑动,只能等超时重传,可靠性没问题但效率有损失。

因此 TCP 引入快速重传机制:当接收方收到丢失数据后面的数据时,会不断发送重复 ACK(如 ACK=1001)。发送方连续收到多个相同 ACK,就能推断"接收方一直在等某个数据,后面的数据已到达",从而不等超时,直接重传可能丢失的数据

注意:快速重传是超时重传的"锦上添花"而非"雪中送炭"。它无法覆盖所有丢包场景——例如数据丢失后后续没有新数据到达,接收方无法产生足够的重复 ACK,此时仍要依靠超时重传。超时重传机制是可靠传输不可或缺的基础,快速重传是在此基础上的性能优化。

3.6 滑动窗口的大小如何确定

窗口太小,连续发送的数据少,仍需频繁等待 ACK,带宽利用不充分;窗口太大,接收方来不及处理,数据堆积甚至缓冲区溢出,造成丢弃与重传,浪费网络资源。

滑动窗口的大小取决于对方的接收能力:滑动窗口大小 = 16 位窗口大小字段(rwnd,接收窗口)。但 TCP 不仅考虑双方通信,还考虑网络环境:

最终:滑动窗口的大小 = min(rwnd, cwnd),实际发送量不能超过这两个窗口允许的范围。

四、流量控制机制

流量控制要解决的问题是:发送方发送速度太快,接收方处理不过来怎么办?

16 位窗口大小字段表示接收方接收缓冲区剩余空间的大小,接收方通过报文持续通告自己的接收能力,发送方据此控制发送量。双方接收能力的交互在三次握手时已经明确,后续通过 ACK 报文动态调整窗口大小。

4.1 零窗口探测

如果接收方缓冲区满了,会把窗口大小设置为 0,发送方收到后将滑动窗口置 0、不再发送数据。那么当接收方处理完数据、缓冲区重新出现空闲时,发送方怎么知道?

发送方发现通告窗口为 0 时并不会永远等待,而是启动一个持续计时器,经过一段时间后主动发送一个不携带数据的 TCP 报文,询问接收方当前窗口大小,接收方通过 ACK 告知。这就是零窗口探测——它的目的不是传输数据,而是避免发送方因零窗口通告而永久陷入等待。

4.2 16 位窗口大小的限制与窗口扩大因子

窗口字段只有 16 位,最大表示 65535 字节,那 TCP 的窗口最大就只有 65535 字节吗?并不是。TCP 报头的选项字段中存在窗口扩大因子(Window Scale)

实际窗口大小 = 窗口字段值 × 2^M(M 为窗口扩大因子)

例如:窗口字段 = 10000,M = 2,实际窗口大小 = 10000 × 4 = 40000 字节。

窗口扩大因子在连接建立过程中协商,连接建立后双方按协商结果解释窗口大小。因此 16 位窗口字段并不代表窗口上限只有 65535 字节。

五、拥塞控制机制

流量控制只解决了接收方的处理能力问题。假设接收方缓冲区足够大、应用处理足够快,发送方就能无限提速吗?答案是否定的——因为发送方和接收方之间还隔着网络本身的承载能力

少量发送方一般不会轻易造成严重拥塞,但当大量主机同时通信时,共享的带宽和网络设备处理能力就可能成为瓶颈(就像旅游景点人多了网速变慢)。如果网络拥塞时发送方仍按原速发送,甚至在丢包后大量重传,会进一步加重网络压力,使数据包不断堆积,通信效率进一步下降。

因此 TCP 必须根据网络当前状况动态调整发送速度,这就是拥塞控制机制。

5.1 拥塞窗口

TCP 用**拥塞窗口(Congestion Window,cwnd)**来考虑"当前网络能够承受多少数据",与考虑"接收方能接收多少数据"的 rwnd 共同限制发送量:

窗口关注对象作用
rwnd(接收窗口)接收方流量控制:接收方还能接收多少数据
cwnd(拥塞窗口)网络拥塞控制:网络能承受多少数据

实际发送滑动窗口 = min(rwnd, cwnd)。例如 rwnd=10000、cwnd=4000,虽然接收方能接收 10000 字节,但网络只能承受 4000 字节,发送方最多只能发 4000 字节;反之 rwnd=4000、cwnd=10000 时,限制发送速度的则是接收方。

简单理解:流量控制关注接收方,拥塞控制关注网络。

5.2 TCP 如何判断网络是否拥塞

TCP 无法直接看到网络内部状态,而是通过传输过程中表现出来的现象判断,最典型的就是数据包丢失

于是 TCP 形成不断"试探网络承载能力"的循环:网络良好 → 增大 cwnd → 提高速度 → 继续观察 → 大量丢包 → 减小 cwnd → 降低速度 → 重新尝试增大 cwnd。这就是 TCP 拥塞控制的核心思想。

5.3 慢启动

刚开始发送数据时,如果 cwnd 一开始就设得很大并立即冲击网络,很可能一开始就造成拥塞。因此 TCP 从较小的拥塞窗口开始,逐渐增加——这就是慢启动(Slow Start)

这里的"慢"不是指传输速度慢,而是指不会一开始就以很大的发送量冲击网络,而是逐渐增加发送量,探索网络能承受的范围。慢启动阶段 cwnd 快速增长:1 → 2 → 4 → 8 → 16 → 32,整体呈指数增长趋势。

5.4 拥塞避免

如果一直指数增长(1 → 2 → 4 → 8 → 16 → 32 → 64 → 128…),cwnd 很快就会超过网络承载能力。因此当 cwnd 增长到一定程度后,TCP 进入**拥塞避免(Congestion Avoidance)**阶段,更谨慎地增加 cwnd:

阶段增长方式特点
慢启动1 → 2 → 4 → 8 → 16 → 32快速探索网络承载能力
拥塞避免32 → 33 → 34 → 35 → 36接近网络承载能力后谨慎提速

5.5 发生网络拥塞后怎么办

TCP 在增大 cwnd 的过程中发现丢包,说明发送速度可能超过了网络承载能力,此时需要降低 cwnd。TCP 有两种发现丢包的方式:

不需要深入具体的窗口调整公式,只需要理解:发生丢包 → TCP 判断网络可能拥塞 → 减小拥塞窗口 → 降低发送速度。网络恢复后,TCP 又重新增大 cwnd,继续探测网络承载能力,如此循环往复。

六、延迟应答机制

接收方每收到一个数据报文就立即返回 ACK,网络中会产生大量 ACK 报文,增加额外开销。因此 TCP 采用延迟应答:收到数据后不立即发送 ACK,而是暂时等待一小段时间;等待期间如果又收到新数据,就可以用一个 ACK 对多个数据进行确认,从而减少 ACK 报文数量。

延迟应答对流量控制还有额外帮助:等待期间应用层可能读走了接收缓冲区中的数据,缓冲区出现更多空闲空间,接收方再发 ACK 时就可以通告更新后的、更大的窗口大小,告诉发送方"我现在还能接收更多数据"。不过需要注意:延迟应答的核心目的仍然是减少 ACK 数量,而不是专门为了扩大窗口

七、捎带应答机制

捎带应答的核心思想:在发送 ACK 的同时,如果本机恰好也有数据要发送,就把 ACK 和数据放在同一个 TCP 报文中发送,从而减少单独 ACK 报文带来的网络开销。

例如服务器在回答客户端问题(发送自己的数据)的同时,也携带了对客户端数据的确认编号——一个报文同时完成"发送自己的数据"和"确认收到的数据"。在上一篇文章中我们已结合序号和确认序号详细介绍过该机制,这里作为提高通信效率的机制补充,保证本章内容的完整性。

八、总结

TCP 并不是依靠某一个单独机制实现可靠通信,而是多个机制相互配合:

机制作用
确认应答机制确认数据是否接收
超时重传机制数据丢失后重新发送
滑动窗口机制允许连续发送多个数据,提高传输效率
快速重传机制尽快发现丢失的数据
流量控制机制防止发送速度超过接收方处理能力
拥塞控制机制防止发送速度超过网络承载能力
延迟应答 + 捎带应答进一步减少网络通信开销

通过这些机制,TCP 在可靠性、传输效率、接收方处理能力、网络承载能力之间进行协调,使数据能够可靠、高效地在网络中传输。

到目前为止,我们讨论的都是"TCP 建立连接之后如何进行数据传输"。新的问题随之而来:TCP 的连接究竟是如何建立的?为什么建立连接需要三次握手?为什么关闭连接需要四次挥手?为什么关闭后还要经历 TIME_WAIT?连接建立与关闭过程中双方状态如何变化?

这些问题属于 TCP 的连接管理机制。下一篇文章,我们将从 TCP 的连接管理入手,详细介绍三次握手、四次挥手、TCP 状态转换以及连接建立与关闭过程中的相关机制。

SEO 关键词

TCP可靠传输、TCP三次握手、TCP四次挥手、超时重传、滑动窗口、快速重传、流量控制、拥塞控制、慢启动、拥塞避免、延迟应答、捎带应答、TCP机制、网络协议、工业互联网

评论(0