TCP 的可靠性
status
category
date
summary
slug
icon
tags
password
TCP 和 UDP 都是网络传输层的协议,在 计算机网络基础:TCP、UDP协议的简单介绍及区别 中简单介绍了它们的区别,最主要的是 TCP 面向连接,并保证了数据传输的可靠性,本文简单介绍了 TCP 采用的实现方案。
确认应答与序列号
在 TCP 中,发送端的数据送达接收端时,接收端会返回一个已收到的通知,这个消息叫做确认应答(ACK)。发送端发送数据之后会等待对方的确认应答,如果没有收到 ACK,则数据丢失的可能性很大,并不代表数据一定丢失,也有可能是对方已经收到,只是 ACK 在途中丢失。但为了保证可靠性,在一定时间内没有等到 ACK,发送端就认为数据已经丢失,并进行重发。
此外,也有可能因为网络较慢等其他原因,导致在发送端重发数据之后才接受到 ACK,虽然没有必要,但这对发送端来说代价不是特别高,然而接收端则会重复接受相同的数据。为了让接收端识别是否已经接收数据、是否需要接收数据,TCP 引入了序列号机制。
序列号是指按顺序给数据的每一个字节都标上号码,接收端查看的 TCP 首部中的序列号和数据长度,将自己下一步应该接收的序列号作为确认应答发送回去。
连接管理
UDP 是一种无连接的通信协议,发送端不检查对方是否可以通信,直接将数据发送出去。TCP 与此相反,在数据通信之前,会通过 TCP 首部发送一个 SYN 包请求建立连接,并等待对方的 ACK 应答。通信结束时也会发送 FIN 包请求断开连接,这时同样等待对方的 ACK 应答。这也就是常说的三次握手建立连接,和四次挥手断开连接。

在握手和挥手的过程中,上面提到的确认应答(ACK)和序列号(seq)都起到了很关键的作用。
流量控制(滑动窗口)
在建立 TCP 连接即握手的同时,两端会在 TCP 首部写入 MMS(Maximum Segment Size) 选项,告诉对方自己适合的最大处理消息长度,然后选择较小的一个作为“段”。TCP 以 1 个段为单位,每发送一个段就进行一次确认应答的处理,这个过程因为需要等待 ACK 所以是同步的,也就意味着包的往返时间越长,通信性能就越低。

为了解决这个问题,TCP 引入了窗口的概念。确认应答不再以每个分段,而是以更大的窗口进行确认,发送端在发送了一个段之后不必要一直等待确认应答。这次相当于将同步的粒度提高到窗口,而原本的同步任务(段的发送和确认)就变成了异步任务。

窗口指的是无需等待确认就可以继续发送数据的最大值,例如上图中窗口大小为 4 个段。这个机制实现了缓冲区,能够同时对多个段进行确认应答。
但只要是同步任务,就有可能造成死锁,只不过是粒度更大的窗口级别的死锁。当 ACK 丢失,发送端在等待 ACK,接收端在等待接受数据,这就造成了死锁。为此 TCP 使用了持续计时器,当一段时间内没有收到 ACK,就查询对方的窗口大小。窗口为 0 则表示对方目前无法接受数据,则重置计时器继续等待;如果对方窗口不为 0,则代表之前的数据丢失了,于是开始重传。这样就避免了死锁的产生。

窗口“滑动”指的就是前面发送的数据不断被确认,窗口可以向后移动到 ACK 中表明的序列号的位置,这样既保证了数据的顺序,又可以同时发送多个段来提高性能。
拥塞控制
为了防止大量数据通信时出现拥堵,TCP 在通信刚刚开始的时候通过“慢启动”算法对数据量进行控制。拥塞窗口表示窗口的大小阈值,慢启动时将其设置为 1 个数据段(或者其他很小的值),之后每收到一次 ACK,拥塞窗口的值就加 1。发送数据包时,比较拥塞窗口和对方通知的窗口大小,发送比它们较小值还要小的数据量。
但数据传输不能始终很慢,拥塞窗口需要不断增长,同时又要保证不能增长过快,这种控制方法叫做拥塞避免算法。随着包的往返,拥塞窗口会以 2 等为底数进行指数增长,为了避免指数爆炸引起网络阻塞,引入了慢启动阈值的概念。TCP 刚刚开始通信时并没有设置慢启动阈值,而是在超时重发时将其设置为当前拥塞窗口一半的大小。如果拥塞窗口的值超过了慢启动阈值,每次收到 ACK,只允许用该比例增大拥塞窗口:
1 个数据段的字节数 × 1 个数据段的字节数 / 拥塞窗口的字节数

上图展现了两种调整拥塞窗口或慢启动阈值的情况:
- 超时重发:将慢启动阈值设置为当前拥塞窗口大小的一半,然后将拥塞窗口大小设置为零,重新开始慢启动。
- 重复确认应答:严格来说,是将慢启动阈值设置为已发送但未收到确认应答的数据量的一半。然后将窗口大小设置为慢启动阈值 + 3 个数据段的大小。
重复确认应答一般的触发条件是收到至少 3 次重复的确认应答,在收到重复确认应答时,发送端不需要等待计时器判断是否超时,而应当立即发送对方没有收到的数据,这称为“快重传”。另外在发生重复确认应答时,并不需要重新从零开始慢启动,这个过程称为“快恢复”。
总结
TCP 连接需要确定双方此时能够通信,并确定数据送达,为此引入了 TCP 连接和确认应答(ACK)等概念;数据发送的速度应该让接收方恰好接收,不至于过快而导致丢失,也不会过慢而导致性能低下,窗口机制既保证了数据的有序,也通过窗口大小来控制流量;而为了过多的数据注入网络,慢启动、拥塞避免、快恢复、快重传等算法保证了拥塞控制。
其中流量控制和拥塞控制看似相同,但是维度不一样。流量控制仅仅针对接收方,接收方需要保证数据来得及接受,也要保证高性能;拥塞控制作用于整个网络,是为了防止数据过多造成的网络负载过大,两者的概念类似于一辆车的速度控制和整个交通的流畅度。
Loading...