我们继续分享 TCP 协议,今天要介绍的是 TCP 协议如何进行流量控制和拥塞控制。在介绍这两个控制机制之前,我们需要先了解窗口的概念。
TCP 数据传输单位
在建立 TCP 连接的同时,也可以确定发送数据包的单位,我们可以将其称为「最大消息长度」(MSS,Maximum Segment Size),最理想的情况下,最大消息长度正好是 IP 中不会被分片处理的最大数据长度。
TCP 在传输大量数据时,是以 MSS 的大小将数据分割发送。重发时也是以 MSS 为单位。
MSS 是在三次握手时,在两端主机之间被计算得出,两端主机在发出建立连接的请求时,会在 TCP 首部写入 MSS 选项,告诉对方自己的接口能够适应的 MSS 的大小,然后会在两者之间选一个比较小的值投入使用。
TCP 以一个段(Segment)为单位,每发送一个段进行一次确认应答的处理,这样的传输方式有一个显著的缺点,就是包往返的时间越长通信性能就越低。
利用窗口控制提高速度
为了解决上述问题,TCP 引入了窗口的概念。在此机制下,确认应答不再以每个分段,而是以更大单位进行确认,也就是说,发送端主机在发送完一个段之后,不必一直等待确认应答,而是继续发送。
窗口的大小就是指无需等待确认应答而可以继续发送数据的最大值,这个机制实现了使用大量的缓冲区(临时保存收发数据的场所),通过对多个段同时进行确认应答的功能,而不是每个分段都返回确认应答,从而大幅度缩短发送时间。
如下图所示,白色高亮的方框就是窗口,在这个窗口内的数据即使没有收到确认应答也可以立即发送出去(在得到确认应答之前,需要在缓冲区保存这部分发送的数据,以便于重发数据):
在滑动窗口以外的部分包括尚未发送的数据以及已经确认对端已经收到的数据,当数据发出后若如期收到确认应答就不再进行重发,此时数据就会从缓冲区中清除,否则丢失的数据需要进行重发(从缓冲区取)。
收到确认应答的情况下,将窗口滑动到确认应答中的序列号的位置,这样就可以顺序将多个段同时发送,提高通信性能。这种机制也被称为滑动窗口控制。
流量控制
发送端会根据自己的实际情况发送数据,但是,接收端可能收到的是一个毫无关系的数据包又可能会在处理其它问题上耗费一些时间,甚至在高负荷的情况下无法接收任何数据。如此一来,如果接收端将本该接收的数据丢弃的话,就又会触发重发机制,从而导致网络流量的无端浪费。
为了防止这种现象的发生,TCP 提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量。这就是所谓的流量控制。
它的具体操作是,接收端主机向发送端主机通知自己可以接收数据的大小,于是发送端会发送不超过这个限度的数据,该大小限制被称作窗口大小。
TCP 首部中,专门有一个字段用来通知窗口大小,接收主机将自己可以接收的缓冲区大小放入这个字段中通知给发送端。这个字段值越大,说明网络的吞吐量越高。
不过,接收端的这个缓冲区一旦面临数据溢出风险,窗口大小的值也会随之被设置为一个更小的值通知给发送端,从而控制数据发送量。也就是说,发送端会根据接收端的指示,对发送数据的量进行控制。这个形成了一个完整的 TCP 流量控制。
拥塞控制
有了 TCP 的窗口控制,收发主机之间即使不再以一个数据段为单位发送确认应答,也能连续发送大量数据包。然而,如果在通信一开始就发送大量数据,容易引发其它问题。
一般来说,计算机网络都处在一个共享的环境,因此,也有可能因为其它主机之间的通信导致网络拥堵,在网络拥堵时,如果发送一个较大量的数据,极有可能导致整个网络的瘫痪。
TCP 为了防止该问题的出现,在通信一开始就会通过一个叫做慢启动的算法得出的值,对发送数据量进行控制。
首先,为了在发送端调节所要发送数据的量,定义了一个叫做「拥塞窗口」的概念,于是在慢启动的时候,将这个拥塞窗口的大小设置为1个数据段(1MSS)发送数据,之后每收到一个确认应答(ACK),就将拥塞窗口的值加1,在发送数据包时,将拥塞窗口的大小与接收端主机通知的窗口大小做比较,然后按照它们当中较小的那个值,发送比它还要小的数据量。
有了这种机制,就可以有效减少通信开始时连续发包导致的网络拥堵。此外,为了防止超时重发时,随着包往返导致的拥塞窗口快速增长(指数增长),引入了慢启动阀值的概念,只要拥塞窗口的大小超过这个阀值,每收到一次确认应答时,只允许以下面这种方式放大拥塞窗口:
拥塞窗口越大,确认应答的数目也会增加,不过每收到一个确认应答,其涨幅也会逐渐减小,甚至小过比一个数据段还要小的字节数。
需要注意的是,TCP 开始通信时,并没有设置慢启动阀值,只有超时重发时才会设置该值,初始值为当时拥塞窗口的一半。
总结起来,用于流量控制的滑动窗口是为了防止把接收端缓存塞满,用于拥塞控制的拥塞窗口是为了防止把网络塞满,导致网络拥塞。TCP 的拥塞控制主要来避免两种现象,包丢失和超时重发。一旦出现了这些现象就说明,发送速度太快了,要慢一点。