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 应答。这也就是常说的三次握手建立连接,和四次挥手断开连接。
notion image
在握手和挥手的过程中,上面提到的确认应答(ACK)和序列号(seq)都起到了很关键的作用。

流量控制(滑动窗口)

在建立 TCP 连接即握手的同时,两端会在 TCP 首部写入 MMS(Maximum Segment Size) 选项,告诉对方自己适合的最大处理消息长度,然后选择较小的一个作为“段”。TCP 以 1 个段为单位,每发送一个段就进行一次确认应答的处理,这个过程因为需要等待 ACK 所以是同步的,也就意味着包的往返时间越长,通信性能就越低。
notion image
为了解决这个问题,TCP 引入了窗口的概念。确认应答不再以每个分段,而是以更大的窗口进行确认,发送端在发送了一个段之后不必要一直等待确认应答。这次相当于将同步的粒度提高到窗口,而原本的同步任务(段的发送和确认)就变成了异步任务。
notion image
窗口指的是无需等待确认就可以继续发送数据的最大值,例如上图中窗口大小为 4 个段。这个机制实现了缓冲区,能够同时对多个段进行确认应答。
但只要是同步任务,就有可能造成死锁,只不过是粒度更大的窗口级别的死锁。当 ACK 丢失,发送端在等待 ACK,接收端在等待接受数据,这就造成了死锁。为此 TCP 使用了持续计时器,当一段时间内没有收到 ACK,就查询对方的窗口大小。窗口为 0 则表示对方目前无法接受数据,则重置计时器继续等待;如果对方窗口不为 0,则代表之前的数据丢失了,于是开始重传。这样就避免了死锁的产生。
notion image
窗口“滑动”指的就是前面发送的数据不断被确认,窗口可以向后移动到 ACK 中表明的序列号的位置,这样既保证了数据的顺序,又可以同时发送多个段来提高性能。

拥塞控制

为了防止大量数据通信时出现拥堵,TCP 在通信刚刚开始的时候通过“慢启动”算法对数据量进行控制。拥塞窗口表示窗口的大小阈值,慢启动时将其设置为 1 个数据段(或者其他很小的值),之后每收到一次 ACK,拥塞窗口的值就加 1。发送数据包时,比较拥塞窗口和对方通知的窗口大小,发送比它们较小值还要小的数据量。
但数据传输不能始终很慢,拥塞窗口需要不断增长,同时又要保证不能增长过快,这种控制方法叫做拥塞避免算法。随着包的往返,拥塞窗口会以 2 等为底数进行指数增长,为了避免指数爆炸引起网络阻塞,引入了慢启动阈值的概念。TCP 刚刚开始通信时并没有设置慢启动阈值,而是在超时重发时将其设置为当前拥塞窗口一半的大小。如果拥塞窗口的值超过了慢启动阈值,每次收到 ACK,只允许用该比例增大拥塞窗口:
1 个数据段的字节数 × 1 个数据段的字节数 / 拥塞窗口的字节数
notion image
上图展现了两种调整拥塞窗口或慢启动阈值的情况:
  1. 超时重发:将慢启动阈值设置为当前拥塞窗口大小的一半,然后将拥塞窗口大小设置为零,重新开始慢启动。
  1. 重复确认应答:严格来说,是将慢启动阈值设置为已发送但未收到确认应答的数据量的一半。然后将窗口大小设置为慢启动阈值 + 3 个数据段的大小。
重复确认应答一般的触发条件是收到至少 3 次重复的确认应答,在收到重复确认应答时,发送端不需要等待计时器判断是否超时,而应当立即发送对方没有收到的数据,这称为“快重传”。另外在发生重复确认应答时,并不需要重新从零开始慢启动,这个过程称为“快恢复”。

总结

TCP 连接需要确定双方此时能够通信,并确定数据送达,为此引入了 TCP 连接和确认应答(ACK)等概念;数据发送的速度应该让接收方恰好接收,不至于过快而导致丢失,也不会过慢而导致性能低下,窗口机制既保证了数据的有序,也通过窗口大小来控制流量;而为了过多的数据注入网络,慢启动、拥塞避免、快恢复、快重传等算法保证了拥塞控制。
其中流量控制和拥塞控制看似相同,但是维度不一样。流量控制仅仅针对接收方,接收方需要保证数据来得及接受,也要保证高性能;拥塞控制作用于整个网络,是为了防止数据过多造成的网络负载过大,两者的概念类似于一辆车的速度控制和整个交通的流畅度。
Loading...

© 刘口子 2018-2025