Fork me on GitHub

传输层协议:UDP与TCP(三)

TCP滑动窗口

TCP的窗口管理将正确接收段的确认和接收端的接收缓冲区分配分离开来。例如,假设接收端有一个4096字节的缓冲区,如下图所示。

tcp21.PNG

详细过程如下:

  1. 如果发送了一个2048字节的数据段,并且该数据段已被正确地接收,那么,接收端将确认该数据段。然而,由于接收端现在只剩下2048字节的缓冲区空间(在应用程序从缓冲区取走数据之前),所以它将宣告下一个期望字节开始窗口为2048。
  2. 发送端又传输了另一个2048字节长的段,该段被确认了,但是接收端宣告的窗口大小变成了0。因此,发送端不得不停止,等待接收主机上的应用程序从缓冲区取走一些数据。到那时候,TCP实体可以向发送端宣告一个更大的窗口,发送端才能发送数据。
  3. 当窗口变为0时,发送端不能如通常那样发送段了,但这里有两种意外情形。第一,紧急数据仍可以发送,比如,允许用户杀掉远程机器上运行的某一个进程。第二,发送端可以发送一个1字节的段,以便强制接收端重新宣告下一个期望的字节和窗口大小,这种数据包称为窗口探测。TCP标准明确地提供了这个选项,来防止窗口更新数据包丢失后发生死锁。
  4. 发送端并不一定一接到应用程序传递来的数据马上将数据传送出去;同样,接收端也不一定必须尽可能快地发送确认段。TCP实体可以充分利用这种自由度来提高传输性能。
TCP性能问题
带宽紧缺

带宽:是指在固定的时间可传输的资料数量,亦即在传输管道中可以传递数据的能力。

在带宽紧缺的场合,在同一时间间隔内多次发送应答报文不合适,会浪费珍贵的带宽资源

解决方法:延迟确认,基本想法是将确认和窗口更新延迟50毫秒,希望能够获得一些数据免费搭载过去。不过尽管通过延迟确认减少了接收端给与网络的负载,但是发送端发送多个小数据包的工作方式依然非常低效。避免这种用法的一种方法是采用Nagle算法:当数据每次以很少量方式进入到发送端时,发送端只是发送第一次到达的数据字节,然后将其余后面到达的字节缓冲起来,直到发送出去的那个数据包被确认。然后将所有缓冲的字节放在一个TCP段中发送出去,并且继续开始缓冲字节,直到下一个段被确认。这种算法可以大大地减少所需的带宽。

当需要一个快速的短数据包流时(比如在Internet上玩互动游戏时),可以禁用Nagle算法

低能窗口综合症

当每次接收端缓冲区只有1个字节的空闲,而发送端也发送一字节,接收端也对这1字节的数据段进行确认,同时设置窗口大小为0。这种行为可能会永久地持续下去。

解决方法:如同发送端的TCP一样,接收端的TCP也可以缓冲数据,它可以阻塞上层应用的读请求,直至它累积来大块的数据。这样做可以减少调用TCP的次数,而从减少额外的开销。当然,这样做也增加了响应的时间,但是,对于像文件传输这样的非交互式应用来说,效率可能比单个请求的响应时间更加重要。

数据段乱序

乱序到达的数据段到达时,没有什么比丢弃乱序到达的段更糟糕的事,因为丢弃这些段,那么它们将被发送端重传。

解决方法:只有当确认字节之前的所有数据都到达之后才能发送确认,这种方法称为累计确认。如果接收端已经获得0、1、2、4、5、6、7,它可以确认直到段2(包括段2)之前的数据。当发送端超时,然后重发段3.因为接收端已经缓冲了段4~段7,一旦它收到段3就可以立即确认直到段7的全部字节。

TCP拥塞控制

当提供给任何网络的负载超过它的处理能力时,拥塞便会产生。Internet也不例外。当路由器上的队列增长到很大时,网络层检测到拥塞,并试图通过丢弃数据包来管理拥塞。传输层接收到从网络层反馈来的拥塞信息,并减慢它发送到网络的流量速率。

TCP的拥塞控制是在AIMD(加法递增乘法递减)的基础山实现的,它使用了一个窗口,并且把丢包当作二进制信号。要做到这一点,TCP维持一个拥塞窗口,窗口大小是任何时候发送端可以往网络发送的字节数。 响应的速率则是窗口大小除以连接的往返时间。TCP根据AIMD规则来调整该窗口的大小。

除了维护一个拥塞窗口外,还有一个流量控制窗口,该窗口指出了接收端可以缓冲的字节数。要并发跟踪这两个窗口,可能发送的字节数是两个窗口中较小的那个。因此,有效窗口是发送端认为的应该大小和接收端认为的应该大小中的较小者。 如果拥塞窗口或流量控制窗口暂时已满,则TCP将停止发送数据。如果接收端说“发送64KB数据”,但发送端直到超过32KB的突发将阻塞网络,它就只发送32KB;另一方面,如果接收端说“发送64KB数据”,发送端知道高达128KB的突发通过网络都毫不费力,它会发送要求的全部64KB。

现代拥塞控制算法
  1. 慢速启动

当建立连接时,发送端用一个很小的值初始化拥塞窗口,最多不超过4个段,然后发送端发送该初始窗口大小的数据。数据包必须通过一个往返时间才被确认。结果是每一个被确认的段允许发送两个段,每经过一个往返时间拥塞窗口增加一倍。

但是,慢启动下按照指数级增长拥塞窗口,当网络管道已经为满时,发送端把额外的数据包放置到网络中将在路由器产生队列,因为它们被传递到接收器的速度不够快。拥塞和丢包即将产生。为了保持对慢速启动的控制,发送端为每个连接维持一个称为慢启动阙值的阙值,最初,这个值被设置得任意高,可以达到流量控制窗口的大小,因此它不会限制连接速度。TCP以慢速启动方式不断增加拥塞窗口,直到发生超时,或者拥塞窗口超过该阙值。每当检测到丢包,比如超时了慢启动阙值就被设置为当前拥塞窗口的一半,整个过程再++~~重新启动~~++。一旦慢启动超过了阙值,TCP就从慢速启动切换到线性增加(即加法递增)。

发送端有一个快速方法来识别它的包已经被丢失。当丢失数据包的后续数据包到达接收端时,它们出发给发送端返回确认。这些段携带着相同的确认号,称为 重复确认 。发送端每次收到重复确认时,很可能另一个包已经到达接收端,而丢失的那个包仍然没有出现。因为包可以选择网络中不同的路径,所以它们可能不按发送顺序到达接收端。这样就会出发重复确认,即使没有数据包丢失。

  1. 快速重传

TCP假设三个重复确认意味着丢失一个包。丢失包的序号可以从确认号推断出来,这个包可以被立即重传,这种启发式机制称为快重传。 重传后,慢启动阙值被设置为当前拥塞窗口的一般,就像发生了超时一样。重新开始慢启动过程,拥塞窗口被设置成一个包。有了这个窗口大小,如果在一个往返时间内确认了该重传的数据包以及丢包之前已发送的所有数据,则发出一个新的数据包。

  1. 快速恢复

在快速重传时,连接还工作在一个太大的拥塞窗口,但它仍然同样以确认时钟 的速率在运行。每次到达另一个重复确认时,可能另一个数据包已经离开网络。使用重复确认来计算网络中的数据包,有可能让一些包离开网络,并继续为每一个额外的重复确认发送一个新的包。,快速恢复就是实现这种行为的启发式机制。这是一个临时模式,其目的是保持拥塞窗口上运行确认时钟,该拥塞窗口有一个新阙值或者快速重传时把拥塞窗口减半。要做到这一点,对重复确认要计数,直到网络内的数据包数量下降到新阙值,当丢失的包都被重传并确认时,重复确认流将停止,快速恢复模式就此退出。拥塞窗口将被设置到新的慢启动阙值,并开始按线性增长。

确认时钟:确认返回到发送端的速率恰好是数据包通过路径上最慢链路时的速率。

这种启发式的结果是TCP避免了慢速启动,只有第一次启动或者发生超时时才进入真正的慢速启动。

其它
  • 选择确认

TCP从一个反复确认流中推断出已经到达和已经丢失的数据包。累计确认号无法提供这种确切的消息。一个简单的解决方法是使用选择确认,该确认列出了3个已接收的字节范围。有了这个信息,发送端在实现拥塞窗口时可以更直接地确定哪些数据包需要重传,并跟踪那些还在途中的数据包。

  • 显式拥塞通知(ECN)

ECN是IP层的机制,主要用来通知主机发生了拥塞,有了它,除了用丢包作为拥塞信号外,TCP也可以接收来自IP的拥塞信号。可以在标识位中设置。