计算机网络 - 第三章 运输层 多路复用 - 多路分解 - UDP - TCP - 拥塞控制

一、概述和运输层服务

运输层协议为运行在不同主机上的应用程序之间提供了逻辑通信功能。

运输层在应用程序进程间提供逻辑的而非物理的通信:

在这里插入图片描述

1.1 运输层和网络层的关系

网络层提供了主机之间的逻辑通信,而运输层为运行在不同主机上的进程之间提供了逻辑通信。

运输层协议只工作在端系统中。在端系统中,运输层协议将来自应用进程的报文移动到网络边缘(即网络层),反过来也是一样,但对有关这些报文在网络核心如何移动并不作任何规定。事实上,中间路由器既不处理也不识别运输层加在应用层报文的任何信息。

计算机网络中可以安排多种传输层协议,每种协议为应用程序提供不同的服务模型。

运输协议能够提供的服务常常受限于底层网络协议的服务模型。如果网络层协议无法为主机之间发送的运输层报文段提供时延或宽带保证的话,运输层协议也就无法为进程之间发送的应用程序报文提供时延或宽带保证。

即使底层网络协议是不可靠的,传输协议也能为应用提供可靠的数据传输服务。即使网络层不能保证运输层报文段的机密性,运输协议也能使用加密来确保应用程序报文不被入侵者读取。

1.2 因特网运输层概述

因特网为应用层提供了两种可用传输协议。

  • UDP(用户数据报协议):它为调用它的应用程序提供了一种不可靠、无连接的服务。
  • TCP(传输控制协议):它为调用它的应用程序提供了一种可靠的、面向连接的服务。

因特网网络层协议有一个名字叫 IP(网际协议)。IP 为主机之间提供了逻辑通信。

IP 的服务模型是尽力而为交付服务。这意味着 IP 尽它 “最大的努力” 在通信的主机之间交付报文段,它不确保报文段的交付,不保证报文段的按序交付,不保证报文段中数据的完整性。

UDP 和 TCP 最基本的责任是,将两个端系统间 IP 的交付服务扩展为运行在端系统上的两个进程之间的交付服务。将主机间交付扩展到进程间交付被称为运输层的多路复用多路分解

UDP 和 TCP 还可以通过在其报文段首部中包括差错检查字段而提供完整性检查。

进程到进程的数据交付和差错检查时两种最低限度的运输层服务,也是 UDP 所能提供的仅有的两种服务。与 IP 一样,UDP 也是一种不可靠的服务,即不能保证一个进程所发送的数据能够完整无缺地(或全部!)到达目的进程。

TCP 提供可靠数据传输。通过使用流量控制、序号、确认和定时器,TCP 确保正确地、按序地将数据从发送进程交付给接收进程。TCP 还提供拥塞控制。TCP 力求为每个通过一条拥塞网络链路的连接平等地共享网络链路带宽。这可以通过调节 TCP 连接的发送端发送进网络的流量速率来做到。

二、多路复用与多路分解

一个进程有一个或多个套接字(socket),它相当于从网络向进程传递数据和从进程向网络传递数据的门户。因此,如图所示,在接收主机中的运输层实际上并没有直接将数据交付给进程,而是将数据交给了一个中间的套接字。由于在任一时刻,在接收主机上可能有不止一个套接字,所有每个套接字都有唯一的标识符。

运输层的多路复用与多路分解:

在这里插入图片描述
每个运输层报文段中具有几个字段。在接收端,运输层检查这些字段,标识出接收套接字,进而将报文段定向到该套接字。将运输层报文段中的数据交付到正确的套接字的工作称为多路分解

在源主机从不同套接字中收集数据块,并为每个数据块封装上首部信息(这将在以后用于分解)从而生成报文段,然后将报文段传递到网络层,所有这些工作称为多路复用

运输层多路复用要求:

  • 套接字有唯一标识符。
  • 每个报文段有特殊字段来指示该报文段所要交付到的套接字。

运输层报文段中的源与目的端口字段:

在这里插入图片描述

如图所示,这些特殊字段是源端口号字段目的端口号字段

端口号是一个 16 比特的数,其大小在 0 ~ 65535 之间。0 ~ 1023 范围的端口号称为周知端口号,是受限制的,这是指它们保留给诸如 HTTP(80)和 FTP(21)之类的周知应用层协议来使用。

当我们开发一个新的应用程序时,必须为其分配一个端口号。

在主机上的每个套接字能够分配一个端口号,当报文段到达主机时,运输层检查报文段中的目的端口号,并将其定向到相应的套接字。然后报文段中的数据通过套接字进入其所连接的进程。

2.1 无连接的多路复用与多路分解

一个 UDP 套接字是由一个二元组全面标识的,该二元组包含一个目的 IP 地址和一个目的端口号。因此,如果两个 UDP 报文段有不同的源 IP 地址和/或源端口号,但具有相同的目的 IP 地址和目的端口号,那么这两个报文段将通过相同的目的套接字被定向到相同的目的进程。

源端口号与目的端口号的反转:

在这里插入图片描述
如图所示,在 A 到 B 的报文段中,源端口号用作 “返回地址” 的一部分,即当 B 需要回发一个报文段给 A 时,B 到 A 的报文段中的目的端口号便从 A 到 B 的报文段中的源端口号中取值(完整的返回地址是 A 的 IP 地址和源端口号)。

2.2 面向连接的多路复用与多路分解

TCP 套接字是由一个四元组(源 IP 地址,源端口号,目的 IP 地址,目的端口号)来标识的。因此,当一个 TCP 报文段从网络到达一台主机时,该主机使用全部 4 个值来将报文段定向(分解)到相应的套接字。

特别与 UDP 不同的是,两个具有不同源 IP 地址或源端口号的到达 TCP 报文段将被定向到两个不同的套接字,除非 TCP 报文段携带了初始创建连接的请求。

服务器主机可以支持很多并行的 TCP 套接字,每个套接字与一个进程相联系,并由其四元组来标识每个套接字。当一个 TCP 报文段到达主机时,所有 4 个字段被用来将报文段定向(分解)到相应的套接字。

两个客户使用相同的目的端口号(80)与同一个 Web 服务器应用通信:

在这里插入图片描述

2.3 Web 服务器与 TCP

连接套接字与进程之间并非总是有着一一对应的关系。事实上,当今的高性能 Web 服务器通常只使用一个进程,但是为每个新的客户连接创建一个具有新连接套接字的新线程(线程可被看作是一个轻量级的子进程)。

如果客户与服务器使用持续 HTTP 报文,则在整条连接持续期间,客户与服务器之间经由同一个服务器套接字交换 HTTP 报文。

如果客户与服务器使用非持续 HTTP,则对每一对请求/相应都创建一个新的 TCP 连接并在随后关闭,因此对每一对请求/响应创建一个新的套接字并在随后关闭。这种套接字的频繁创建和关闭会严重地影响一个繁忙的 Web 服务器性能。

三、无连接运输:UDP

由 [ RFC 768 ] 定义的 UDP 只是做了运输协议能够做的最少工作。除了复用/分解功能及少量的差错检测外,它几乎没有对 IP 增加别的东西。

UDP 从应用程序得到数据,附加上用于多路复用/分解服务的源和目的端口号字段,以及两个其他的小字段,然后将形成的报文段交给网络层。网络层将该运输层报文封装到一个 IP 数据报中,然后尽力而为地尝试将此报文交付给接收主机。如果该报文段到达接收主机,UDP 使用目的端口号将报文段中的数据交付给正确的应用进程。

使用 UDP时,在发送报文段之前,发送方和接收方的运输层实体之间没有握手。因此,UDP 是无连接的。

DNS 是一个通常使用 UDP 的应用层协议的例子。当一台主机中的 DNS 应用程序想要进行一次查询时,它构造了一个 DNS 查询报文并将其交给 UDP。无须执行任何与运行在目的端系统中的 UDP 实体之间的握手,主机端的 UDP 为此报文添加首部字段,然后将形成的报文段交给网络层。网络层将此 UDP 报文段封装进一个 IP 数据报中,然后将其发送给一个名字服务器。在查询主机中的 DNS 应用程序则等待对该查询的响应。如果它没有收到响应,则要么试图向另一个名字服务器发送该查询,要么通知调用的应用程序它不能获得响应。

UDP 相对于 TCP 的优点:

  • 关于发送什么数据以及何时发送的应用层控制更为精细。采用 UDP 时,只要应用进程将数据传递给 UDP,UDP 就会将此数据打包进 UDP 报文段并立即将其传递给网络层。TCP 有一个拥塞控制机制,以便当源和目的主机间的一条或多条链路变得极其拥塞时来遏制运输层 TCP 发送方。
  • 无须连接建立。TCP 在开始数据传输之前要经过三次握手。UDP 却不需要任何准备即可进行数据传输。因此 UDP 不会引入建立连接的时延。
  • 无连接状态。TCP 需要在端系统中维护连接状态。UDP 不维护连接状态,也不跟踪这些参数。
  • 分组首部开销小。每个 TCP 报文段都有 20 字节的首部开销,而 UDP 仅有 8 字节的开销。

流行的因特网应用及其下面的运输协议:

在这里插入图片描述
使用 UDP 的应用时可能实现可靠数据传输的。这可通过在应用程序自身中建立可靠性机制来完成。将可靠性直接构建于应用程序中可以使其进行可靠通信,而无须受制于由 TCP 拥塞控制机制强加的传输速率限制。

3.1 UDP 报文段结构

UDP 报文段结构:

在这里插入图片描述
应用层数据占用 UDP 报文段的数据字段。UDP 首部只有 4 个字段,每个字段由两个字节组成。通过端口号可以使目的主机将应用数据交给运行在目的端系统中的相应进程(即执行分解功能)。长度字段指示了在 UDP 报文段中的字节数(首部加数据)。接收方使用检验和来检查在该报文段中是否出现了差错。

3.2 UDP 检验和

UDP 检验和提供了差错检测功能。检验和用于确定当 UDP 报文段从源到达目的地移动时,其中的比特是否发生了改变。

发送方的 UDP 对报文段中的所有 16 比特字的和进行反码运算,求和时遇到的任何溢出都被回卷。得到的结果被放在 UDP 报文段中的检验和字段。

在既无法确保逐链路的可靠性,又无法确保内存中的差错检测的情况下,如果端到端数据传输服务要提供差错检测,UDP 就必须在端到端基础上在运输层提供差错检测。

四、可靠数据传输原理

可靠数据传输:服务模型与服务实现:

在这里插入图片描述

实现这种服务抽象是可靠数据传输协议的责任。

4.1 构造可靠数据传输协议

4.1.1 经完全可靠信道的可靠数据传输:rdt1.0

rdt1.0:用于完全可靠信道的协议。

在这里插入图片描述
图显示了 rdt1.0 发送方和接收方的有限状态机(FSM)的定义。

引起变迁的事件显示在表示变迁的横线上方,事件发生时所采取的动作显示在横线下方。

FSM 的初始状态用虚线表示。

发送端:

  • rdt_send(data):接收来自高层的数据。
  • packet = make_pkt(data):产生一个包含待发送数据的分组。
  • udt_send(packet):将分组发送到信道中。

接收端:

  • rdt_rcv(packet):从底层信道接收一个分组。
  • extract(packet, data):从分组中取出数据。
  • deliver_data(data):将数据上传给较高层。

4.1.2 经具有比特差错信道的可靠数据传输:rdt2.0

底层信道更为实际的模型是分组中的比特可能受损的模型。

现实中,口述报文协议使用了肯定确认(“OK”)与否认确认(“请重复一遍”)。这些控制报文使得接收方可以让发送方知道哪些内容被正确接收,哪些内容接收有误并因此需要重复。在计算机网络环境中,基于这样重传机制的可靠数据传输协议称为自动重传请求(ARQ)协议

ARQ 协议中还需要另外三种协议功能来处理存在比特差错的情况:

  • 差错检测。首先,需要一种机制以使接收方检测到何时出现了比特差错。
  • 接收方反馈。发送方要了解接收方情况的唯一途径就是让接收方提供明确的反馈信息给发送方。
  • 重传。接收方收到有差错的分组时,发送方将重传该分组文。

rdt2.0:用于具有比特差错信道的协议。
在这里插入图片描述
图说明了表示 rdt2.0 的 FSM,该数据传输协议采用了差错检测、肯定确认与否定确认。

如果对一个事件没有动作,或没有就事件发生而采取了一个动作,我们将在横线上方或下方使用符号 ∧,以分别明确地表示缺少动作或事件。

当发送端处于等待 ACK 或 NAK 的状态时,他不能从上层获得更多的数据。

发送端:

  • rdt_send(data):接收来自高层的数据。
  • sndpket = make_pkt(data, checksum):产生一个包含待发送数据的带校验和的分组。
  • udt_send(sndpkt):将分组发送到信道中。
  • rdt_rcv(rcvpkt) && isNAK(rcvpkt):等待来自接收方的 NAK 分组。
  • udt_send(sndpkt):将分组发送到信道中。
  • rdt_rcv(rcvpkt) && isACK(rcvpkt):等待来自接收方的 ACK 分组。

接收端:

  • rdt_rcv(rcvpkt) && corrupt(rcvpkt):从底层信道接收一个受损的分组。
  • sndpkt = make_pkt(NAK):产生一个 NAK 分组。
  • udt_send(sndpkt):将分组发送到信道中。
  • rdt_rcv(rcvpkt) && notcorrupt(rcvpkt):从底层信道接收一个未受损的分组。
  • extract(rcvpkt, data):从分组中取出数据。
  • deliver_data(data):将数据上传给较高层。
  • sndpkt = make_pkt(ACK):产生一个 ACK 分组。
  • udt_send(sndpkt):将分组发送到信道中。

如果一个 ACK 或 NAK 分组受损,发送方无法知道接收方是否正确接收了上一块发送的数据。

考虑处理受损 ACK 和 NAK 时的 3 种可能性:

  • 在协议中引入一种新型发送方到接收方的分组。如果发送方不理解来自接收方的回答,发送方发送该新型分组到接收方,接收方将复述其回答。
  • 增加足够的检验和比特,使发送方不仅可以检测差错,还可以恢复差错。
  • 当发送方收到含糊不清的 ACK 或 NAK 分组时,只需重传当前数据分组即可。然而,这种方法在发送方到接收方的信道中引入了冗余分组。冗余分组的根本困难在于接收方不知道它上次所发送的 ACK 或 NAK 是否被发送方正确地收到。因此它无法事先知道接收到的分组是新的还是一次重传。

解决这个新问题的一个简单方法是在数据分组中添加一新字段,让发送方对其数据分组编号,即将发送数据分组的序号放在该字段。于是,接收方只需要检查序号即可确定收到的分组是否一次重传。

rdt2.1 发送方:

在这里插入图片描述

rdt2.1 接收方:

在这里插入图片描述

rdt2.1 的发送方和接收方 FSM 的状态数都是以前的两倍。这是因为协议状态此时必须反映出目前(由发送方)正发送的分组或(在接收方)希望接收的分组是 0 还是 1。发送或期望接收 0 号分组的状态中的动作与发送或接收 1 号分组的状态中的动作是相似的;唯一的不同是序号处理的方法不同。

协议 rdt2.1 使用了从接收方到发送方的肯定确认和否定确认。当接收到失序的分组时,接收方对所接收的分组发送一个肯定确认。如果收到受损的分组,则接收方将发送一个否定确认。如果不发送 NAK,而是对上次正确接收的分组发送一个 ACK(即接收冗余 ACK)后,就知道接收方没有正确接收到跟在别确认两次的分组后面的分组。

rdt2.2 发送方:

在这里插入图片描述

rdt2.2 接收方:

在这里插入图片描述
rdt2.2 是在有比特差错信道上实现的一个无 NAK 的可靠数据传输协议。rdt2.1 和 rdt2.2 之间的细微变化在于,接收方此时必须包括由一个 ACK 报文所确认的分组序号,发送方此时必须检查接收到的 ACK 报文中被确认的分组序号。

4.1.3 经具有比特差错的丢包信道的可靠数据传输:rdt3.0

假定发送方传输一个数据分组,该分组或者接收方对该分组的 ACK 发生了丢失。在这两种情况下,发送方都收不到应当到来的接收方的响应。如果发送方愿意等待足够长的实际以便确定分组已丢失,则它只需要重传该数据分组即可。

实践中采取的方法是发送方明智地选择一个时间值,以判定可能发生了丢包(尽管不能确保)。如果在这个时间内没有收到 ACK,则重传该分组。注意到如果一个分组经历了一个特别大的时延,发送方可能会重传该分组,即使该数据分组及其 ACK 都没有丢失。这就在发送方到接收方的信道中引入了冗余数据分组的可能性。

为了实现基于时间的重传机制,需要一个倒计数定时器,在一个给定的时间量过期后,可中断发送方。因此,发送方需要能做到:

  • 每次发送一个分组(包括第一次分组和重传分组)时,便启动一个定时器。
  • 响应定时器中断(采取适当的动作)。
  • 终止定时器。

rdt3.0 发送方:

在这里插入图片描述
rdt3.0 是一个在可能出错和丢包的信道上可靠传输数据的协议。

因为分组序号在 0 和 1 之间交替,因此 rdt3.0 有时被称为比特交替协议

rdt3.0 的运行,比特交替协议:

在这里插入图片描述
在这里插入图片描述

4.2 流水线可靠数据传输协议

rdt3.0 性能问题的核心在于它是一个停等协议。停等协议有着非常低的发送方利用率。

这种特殊的性能问题的一个简单解决方法是:不以停等方式运行,允许发送多个分组而无须等待确认,如图所示,如果发送方可以在等待确认之前发送 3 个报文,其利用率也基本上提高 3 倍。

因为许多从发送方向接收方输送的分组可以被看成是填充到一条流水线中,故这种技术被称为流水线

停等和流水线发送:

在这里插入图片描述
在这里插入图片描述

流水线技术对可靠数据传输协议可带来如下影响:

  • 必须增加序号范围,因为每个输送中的分组(不计算重传的)必须有一个唯一的序号,而且也许有多个在输送中的未确认报文。
  • 协议的发送方和接收方两端也许不得不缓存多个分组。
  • 所需序号范围和对缓冲的要求的要求取决于数据传输协议如何处理丢失、损坏及时延过大的分组。解决流水线的差错恢复有两种基本方法是:回退N步选择重传

4.3 回退 N 步

回退 N 步(GBN)协议中,允许发送方发送多个分组(当有多个分组可用时)而不需等待确认,但它也受限于在流水线中未确认的分组数不能超过某个最大允许数 N。

在 GBN 中发送方看到的序号:

在这里插入图片描述
如图所示,那些已被发送但还未被确认的分组的许可序号范围可以被看成是一个在序号范围内长度为 N 的窗口。随着协议的运行,该窗口在序号空间向前滑动。因此,N 常被称为窗口长度,GBN 协议也常被称为滑动窗口协议

GBN 发送方的扩展 FSM 描述:

在这里插入图片描述

GBN 接收方的扩展 FSM 描述:

在这里插入图片描述
GBN 发送方必须响应三种类型的事件:

  • 上层的调用。当上层调用 rdt_send() 时,发送方首先检查发送窗口是否已满,即是否有 N 个已发送但未被确认的分组。如果窗口未满,则产生一个分组并将其发送,并相应地更新变量。如果窗口已满,发送方只需将数据返回给上层,隐式地指示上层该窗口已满。然后上层可能会过一会儿再试。
  • 收到一个 ACK。在 GBN 协议中,对序号为 n 的分组的确认采取累积确认的方式,表明接收方已正确接收到序号为 n 的以前且包括 n 在内的所有分组。
  • 超时事件。协议的名字 “回退 N 步” 来源于出现丢失和时延过长分组时发送方的行为。如果出现超时,发送方重传所有已发送但还未被确认过的分组。

在 GBN 协议中,如果一个序号为 n 的分组被正确接收到,并且按序(即上一次交付给上层的数据是序号为 n - 1 的分组),则接收方为分组 n 发送一个 ACK,并将分组中的数据部分交付到上层。在所有其他情况下,接收方丢弃该分组,并为最近按序接收的分组重新发送 ACK。

在 GBN 协议中,接收方丢弃所有失序分组。这种方法的优点是接收缓存简单,即接收方不需要缓存任何失序分组。缺点是随后对该分组的重传也许会丢失或出错,因此甚至需要更多的重传。

运行中的 GBN:

在这里插入图片描述

4.4 选择重传

GBN 本身也有一些情况存在着性能问题。尤其是当窗口长度和带宽时延积都很大时,在流水线中会有很多分组更是如此。单个分组的差错就能引起 GBN 重传大量分组,许多分组根本没有必要重传。随着信道差错率的增加,流水线可能会被这些不必要重传的分组所充斥。

选择重传(SR)协议通过让发送方仅重传那些它怀疑在接收方出错(即丢失或受损)的分组而避免了不必要的重传。这种个别的、按需的重传要求接收方逐个地确认正确接收的分组。再次用窗口长度 N 来限制流水线中未完成、未被确认的分组数。然而,与 GBN 不同的是,发送方已经收到了对窗口中某些分组的 ACK。

选择重传(SR)发送方与接收方的序号空间:

在这里插入图片描述

SR 发送方的事件与动作:

在这里插入图片描述

SR 接收方的事件与动作:

在这里插入图片描述

SR 接收方将确认一个正确接收的分组而不管其是否按序。失序的分组将被缓存直到所有丢失分组(即序号更小的分组)皆被收到为止,这时才可以将一批分组按序交付给上层。

在这里插入图片描述

SR 接收方窗口太大的困境:是一个新分组还是一次重传。

在这里插入图片描述
在这里插入图片描述
图中的两种情况是同等的。没有办法区分是第 1 个分组的重传还是第 5 个分组的初次传输。显然,窗口长度比序号空间小 1 时协议无法工作。窗口长度必须小于或等于序号空间大小的一半。

可靠数据传输机制及其用途的总结:

在这里插入图片描述

五、面向连接的传输:TCP

5.1 TCP 连接

TCP 被称为是面向连接的,这是因为在一个应用进程可以开始向另一个应用进程发送数据之前,这两个进程必须先互相 “握手”,即它们必须互相发送某些预备报文,以建立确保数据传输的参数。作为 TCP 连接建立的一部分,连接的双方都将初始化与 TCP 连接相关的许多 TCP 状态变量。

TCP 连接也总是点对点的,即在单个发送方与单个接收方之间的连接。

TCP 发送缓存和接收缓存:

在这里插入图片描述
TCP 连接建立过程:客户首先发送一个特殊的 TCP 报文段,服务器用另一个特殊的 TCP 报文段来响应,最后,客户再用第三个特殊报文段作为响应。前两个报文段不承载 “有效载荷”,也就是不包含应用层数据;而第三个报文段可以承载有效载荷。

一旦建立起一条 TCP 连接,两个应用进程之间就可以互相发送数据了。客户进程通过套接字传递数据流。数据一旦通过该门,它就由客户中运行的 TCP 控制了。TCP 将这些数据引导到该连接的发送缓存里。接下来 TCP 就会不时从发送缓存里取出一块数据,并将数据传递到网络层。

TCP 可从缓存中取出并放入报文段中的数据数量受限于最大报文段长度(MSS)。MSS 通常根据最初确定的由本地发送主机发送的最大链路层帧长度(即所谓的最大传输单元(MTU))来设置。设置该 MSS 要保证一个 TCP 报文段(当封装在一个 IP 数据报中)加上 TCP/IP 首部长度(通常 40 字节)将适合单个链路层帧。以太网和 PPP 链路层协议都具有 1500 字节的 MTU,因此 MSS 的典型值为 1460 字节。

TCP 为每块客户数据配上一个 TCP 首部,从而形成多个 TCP 报文段。这些报文段被下传给网络层,网络层将其分别封装在网络层 IP 数据报中。然后这些 IP 数据报被发送到网络中。当 TCP 在另一端收到一个报文段后,该报文段的数据就被放入该 TCP 连接的接收缓存中。

5.2 TCP 报文段结构

TCP 报文段由首部字段和一个数据字段组成。数据字段包含一块应用数据。

TCP 报文段结构:

在这里插入图片描述
与 UDP 一样,首部包括源端口号目的端口号,它被用于多路复用/分解来自或送到上层应用的数据。另外,同 UDP 一样,TCP 首部也包括检验和字段。TCP 报文段还包含下列字段:

  • 32 比特的序号字段和 32 比特的确认号字段。这些字段被 TCP 发送方和接收方用来实现可靠数据传输服务。
  • 16 比特的接收窗口字段,该字段用于流量控制。
  • 4 比特的首部长度字段,该字段指示了以 32 比特的字为单位的 TCP 首部长度。由于 TCP 选项字段的原因,TCP 首部的长度是可变的。(通常,选项字段为空,所以 TCP 首部的典型长度是 20 字节。)
  • 可选与边长的选项字段,该字段用于发送方与接收方协商最大报文段长度(MSS)时,或在高速网络环境下用作窗口调节因子时使用。首部字段中还定义了一个时间戳选项。
  • 6 比特的标志字段ACK 比特用于指示确认字段中的值是有效的,即该报文段包括一个对已被成功接收报文段的确认。RSTSYNFIN 比特用于连接建立和拆除。在明确拥塞通告中使用了 CWRECE 比特。当 PSH 比特被置位时,就指示接收方应立即将数据交给上层。最后,URG 比特用来指示报文段里存在着被发送端的上层实体置为 “紧急” 的数据。紧急数据的最后一个字节由 16 比特的紧急数据指针字段指出。当紧急数据存在并给出指向紧急数据尾指针的时候,TCP 必须通知接收端的上层实体。

5.2.1 序号和确认号

TCP 报文段首部中两个最重要的字段是序号字段和确认号字段。这两个字段是 TCP 可靠传输服务的关键部分。

TCP 把数据看成一个无结构的、有序的字节流。我们从 TCP 对序号的使用上可以看出这一点,因为序号是建立在传送的字节流之上,而不是建立在传送的报文段的序列之上。一个报文段的序号因此是该报文报文段首字节的字节流编号。

TCP 是全双工的,因此主机 A 在向主机 B 发送数据的同时,也许也接收来自主机 B 的数据(都是同一条 TCP 连接的一部分)。从主机 B 到达的每个报文段中都有一个序号用于从 B 流向 A 的数据。主机 A 填充进报文段的确认号是主机 A 期望从主机 B 收到的下一字节的序号

因为 TCP 只确认该流中至第一个丢失字节为止的字节,所以 TCP 被称为提供累积确认

5.2.2 Telnet:序号和确认号的一个学习案例

Telnet 是一个用于远程登录的流行应用层协议。它运行在 TCP 之上,被设计成可在任意一对主机之间工作。

假设主机 A 发起一个与主机 B 的 Telnet 会话。因为是主机 A 发起该会话,因此它被标记为客户,而主机 B 被标记为服务器。

一个经 TCP 的简单 Telnet 应用的确认号和序号:

“回显” 用于确保由 Telnet 用户发送的字符已经被远程主机收到并在远程站点上得到处理。

在这里插入图片描述
如图所示,假设客户和服务器的起始序号是 42 和 79。一个报文的序号就是该报文段数据字段首字节的序号。因此,客户发送的第一个报文段的序号为 42,服务器发送的第一个报文段的序号为 79。在 TCP 连接建立后但没有发送任何数据之前,该客户等待字节 79,而该服务器等待字节 42。

5.3 往返时间的估计与超时

5.3.1 估计往返时间

报文段的样本 RTT(表示为 SampleRTT)就是从某报文段被发出(即交给 IP)到对该报文段的确认被收到之间的时间量。大多数 TCP 的实现仅在某个时刻做一次 SampleRTT 测量,而不是为每个发送的报文段测量一个 SampleRTT。

由于路由器的拥塞和端系统负载的变化,这些报文段的 SampleRTT 值会随之波动。由于这种波动,任何给定的 SampleRTT 值也许都是非典型的。

TCP 维持一个 SampleRTT 的加权平均值(称为 EstimatedRTT)。一旦获得一个新 SampleRTT 时,TCP 就会根据计算公式来更新 EstimatedRTT。

5.3.2 设置和管理重传超时间隔

TCP 超时间隔(TimeoutInterval)设为 EstimatedRTT 加上一定余量(DevRTT)。当 SampleRTT 值波动较大时,这个余量应该大些;当波动较小时,这个余量应该小些。

推荐的初始 TimeoutInterval 值为 1 秒。同时,当出现超时后,TimeoutInterval 值将加倍,以免即将被确认的后继报文过早出现超时。然而,只要收到报文段并更新 EstimatedRTT,就使用上述公式再次计算 TimeoutInterval。

5.4 可靠数据传输

TCP 在 IP 不可靠的尽力而为服务之上创建了一种可靠数据传输服务。TCP 的可靠数据传输服务确保一个进程从其接收缓存中读出的数据流是无损坏、无间隙、非冗余和按序的数据流;即该字节流与连接的另一方端系统发送出的字节流是完全相同的。

/* 假设发送方不受 TCP 流量和拥塞控制的限制,来自上层数据的长度小于 MSS,且数据传送只在一个方向进行。 */

NextSeqNum = InitialSeqNumber
SendBase = InitialSeqNumber

loop (永远) {
	switch (事件)
		事件: 从上面应用程序接收到数据 e
			生成具有序号 NextSeqNum 的 TCP 报文段
			if (定时器当前没有运行)
				启动定时器
			向 IP 传递报文段
			NextSeqNum = NextSeqNum + length(data)
			break;
		事件: 定时器超时
			重传具有最小序号但仍未应答的报文段
			启动定时器
			break;
		事件: 收到 ACK,具有 ACK 字段值 y
			if (y > SendBase) {
				SendBase = y;
				if (当前有未被确认的报文段)
					启动定时器
			}
			break;
} /* 结束永远循环 */

5.4.1 一些有趣的情况

第一种情况,主机 A 向主机 B 发送一个报文段。假设该报文段的序号是 92,而且包含 8 字节数据。在发出该报文段之后,主机 A 等待一个来自主机 B 的确认号为 100 的报文段。虽然 A 发出的报文在主机 B 上被收到,但从主机 B 发往主机 A 的确认报文丢失了。在这种情况下,超时事件就会发生,主机 A 会重传相同的报文段。当然,当主机 B 收到该重传的报文段时,它将通过序号发现该报文段包含了早已收到的数据。因此,主机 B 中的 TCP 将丢弃该重传的报文段中的这些字节。

在这里插入图片描述
第二种情况中,主机 A 连续发回了两个报文段。第一个报文段序号是 92,包含 8 字节数据;第二个报文段序号是 100,包含 20 字节数据。假设两个报文段都完好无损地到达主机 B,并且主机 B 为每一个报文段分别发送一个确认。第一个确认报文的确认号是 100,第二个确认报文的确认好是 120。现在假设在超时之前这两个报文段中没有一个确认报文到达主机 A。当超时事件发生时,主机 A 重传序号 92 的第一个报文段,并重启定时器。只有第二个报文段的 ACK 在新的超时发生以前到达,则第二个报文段将不会被重传。

在这里插入图片描述
在第三种情况中,假设主机 A 与在第二种情况中完全一样,发送两个报文段。第一个报文段的确认报文在网络丢失,但在超时事件发生之前主机 A 收到一个确认号为 120 的确认报文。主机 A 因而知道主机 B 已经收到了序号为 119 及之前的所有字节;所有主机 A 不会重传这两个报文段中的任何一个。

在这里插入图片描述

5.4.2 超时间隔加倍

定时器过期很可能是由网络拥塞引起的,即太多的分组到 达源与目的地之间路径上的一台(或多台)路由器的队列中,造成分组丢失或长时间的排队时延。在拥塞的时候,如果源持续重传分组,会使拥塞更加严重。相反,TCP 使用更文雅的方式,每个发送方的重传都是经过越来越长的时间间隔后进行的。

5.4.3 快速重传

超时重传存在的问题之一是超时周期可能相对较长。当一个报文段丢失时,这种长超时周期迫使发送方延迟重传丢失的分组,因而增加了端到端时延。发送方通常可在超时事件发生之前通过注意冗余 ACK 来较好地检测到丢包情况。

冗余 ACK 就是再次确认某个报文段的 ACK,而发送方先前已经收到对该报文段的确认。

产生 TCP ACK 的建议 [ RFC 5681 ]:

在这里插入图片描述
如果 TCP 发送方接收到对相同数据的 3 个冗余 ACK,它把这当作一种指示,说明跟在这个已被确认过 3 次的报文段之后的报文段已经丢失。一旦收到 3 个冗余 ACK,TCP 就执行快速重传,即在该报文段的定时器过期之前重传丢失的报文段。

事件: 收到 ACK,具有 ACK 字段值 y
	if (y > SendBase) {
		SendBase = y
		if (当前有未被确认的报文段)
			启动定时器
	} else {
	 	/* 对已经确认的报文段的一个冗余 ACK */
		对 y 收到的冗余 ACK 数加 1
		if (对 y == 3 收到的冗余 ACK 数)
			/* TCP 快速重传 */
			重新发送具有序号 y 的报文段
	}
	break;

在某报文段的定时器过期之前重传丢失的报文段:

在这里插入图片描述

5.4.4 是回退 N 步还是选择重传

TCP 确认是累积式的,正确接收但失序的报文段是不会被接收方逐个确认的。因此,TCP 发送方仅需维持已发送过但未被确认的字节的最小序号(SendBase)和下一个要发送的字节的序号(NextSeqNum)。在这种意义下,TCP 看起来更像一个 GBN 风格的协议。但是 TCP 和 GBN 协议之间有着一些显著的区别。许多 TCP 实现会将正确接收但失序的报文段缓存起来。

对 TCP 提出的一种修改意见是所谓的选择确认,它允许 TCP 接收方有选择地确认失序报文段,而不是累积地确认最后一个正确接收的有序报文段。当将该机制与选择重传机制结合起来使用时(即跳过重传哪些已被接收方选择性地确认过的报文段),TCP 看起来就像通常的 SR 协议。

5.5 流量控制

一条 TCP 连接的每一侧主机都为该连接设置了接收缓存。当该 TCP 连接收到正确、按序的字节后,它就将数据放入接收缓存。相关联的应用进程会从该缓存中读取数据,但不必是数据刚一到达就立即读取。如果某应用程序读取数据时相对缓慢,而发送方发送得太多、太快,发送的数据就会很容易地使该连接的接收缓存溢出。

TCP 为它的应用程序提供了流量控制服务以消除发送方使接收方缓存溢出 的可能性。流量控制因此是一个速度匹配服务,即发送方的发送速率与接收方应用程序的读取速率相匹配。

TCP 发送方也可能因为 IP 网络的拥塞而被遏制;这种形式的发送方的控制被称为拥塞控制

TCP 通过让发送方维护一个称为接收窗口的变量来提供流量控制。接收窗口用于给发送方一个指示——该接收方还有多少可用的缓存空间。因为 TCP 是全双工通信,在连接两端的发送方都各自维护一个接收窗口。

假设主机 A 通过一条 TCP 连接向主机 B 发送一个大文件。主机 B 为该连接分配了一个接收缓存,并用 RcvBuffer 来表示其大小。主机 B 上的应用进程不时地从该缓存中读取数据。定义以下变量:

  • LastByteRead:主机 B 上的应用进程从缓存读出的数据流的最后一个字节的编号。
  • LastByteRcvd:从网络中到达的并且已放入主机 B 接收缓存中的数据流的最后一个字节的编号。

由于 TCP 不允许已分配的缓存溢出,下式必须成立:

LastByteRcvd - LastByteRead <= RcvBuffer

接收窗口用 rwnd 表示,根据缓存可用空间的数量来设置:

rwnd = RcvBuffer - [ LastByteRcvd - LastByteRead ]

由于该空间是随着时间变化的,所以 rwnd 是动态的。

接收窗口(rwnd)和接收缓存(RcvBuffer):

在这里插入图片描述
主机 B 通过把当前的 rwnd 值放入它发给主机 A 的报文段接收窗口字段中,通知主机 A 它在该连接的缓存中还有多少可用空间。开始时,主机 B 设定 rwnd = RcvBuffer。

主机 A 轮流跟踪两个变量,LastByteSent 和 LastByteAcked。这两个变量的差 LastByteSent - LastByteAcked,就是主机 A 发送到连接中但未别确认的数据量。通过将未确认的数据量控制在值 rwnd 以内,就可以保证主机 A 不会使主机 B 的接收缓存溢出。因此,主机 A 在该连接的整个生命周期须保证:

LastByteSent - LastByteAcked <= rwnd

TCP 规范中要求:当主机 B 的接收窗口为 0 时,主机 A 继续发送只有一个字节数据的报文段。这些报文将会被接收方确认。最终缓存将开始清空,并且确认报文里将包含一个非 0 的 rwnd 值。

5.6 TCP 连接管理

客户中的 TCP 会用以下方式与服务器中的 TCP 建立一条 TCP 连接:

  • 第一步:客户端的 TCP 首先向服务器的 TCP 发送一个特殊的 TCP 报文段。该报文段中不包含应用层数据。但是在报文段的首部中的一个标志位(即 SYN 比特)被置为 1。因此,这个特殊报文段被称为 SYN 报文段。另外,客户会随机地选择一个初始序号(client_isn),并将此编号放置于该起始的 TCP SYN 报文段的序号字段中。该报文段会被封装在一个 IP 数据报中,并发送给服务器。
  • 第二步:一旦包含 TCP SYN 报文段的 IP 数据报到达服务器主机,服务器会从该数据报中提取出 TCP SYN 报文段,为该 TCP 连接分配 TCP 缓存和变量,并向该客户 TCP 发送允许连接的报文段。这个允许连接的报文段也不包含应用层数据。报文段的首部包含 3 个重要的信息。首先,SYN 比特被置为 1。其次,该 TCP 报文段首部的确认号字段被置为 client_isn + 1。最后,服务器选择自己的初始序号(server_isn),并将其放置到 TCP 报文段首部的序号字段中。该允许连接的报文段被称为 **SYNACK 报文段
  • 第三步:在收到 SYNACK 报文段后,客户也要给该连接分配缓存和变量。客户主机则向服务器发送另外一个报文段;这最后一个报文段对服务器的允许连接的报文段进行了确认(该客户通过将值 server_isn + 1 放置到 TCP 报文段首部的确认字段中来完成此项工作)。因为连接已经建立了,所以该 SYN 比特被置为 0。该三次握手的第三个阶段可用在报文段负载中携带客户到服务器的数据。

一旦完成这 3 个步骤,客户和服务器主机就可以互相发送包括数据的报文段了。在以后每一个报文段中,SYN 比特都将被置为 0。

TCP 三次握手:报文段交换。

在这里插入图片描述
参与一条 TCP 连接的两个进程中的任何一个都能终止该连接。当连接结束后,主机中的 “资源”(即缓存和变量)将被释放。

假设某客户打算关闭连接,客户应用进程发出一个关闭连接命令。这会引起客户 TCP 向服务器进程发送一个特殊的 TCP 报文段。这个特殊的报文段让其首部中的一个标志位即 FIN 比特被设置为 1。当服务器接收到该报文段后,就向发送方回送一个确认报文段。然后,服务器发送它自己的终止报文段,其 FIN 比特被置为 1。当服务器接收到该报文段后,就向发送方回送一个确认报文段。然后,服务器发送它自己的终止报文段,其 FIN 比特被置为 1。最后,该客户对这个服务器的终止报文进行确认。此时,在两台主机上用于该连接的所有资源都被释放了。

关闭一条 TCP 连接:

在这里插入图片描述

在一个 TCP 连接的生命周期内,运行在每台主机中的 TCP 协议在各种 TCP 状态之间变迁。

客户 TCP 经历的典型的 TCP 状态序列:

在这里插入图片描述
客户 TCP 开始时处于 CLOSED(关闭)状态。客户的应用程序发起一个新的 TCP 连接。这引起客户中的 TCP 向服务器中的 TCP 发送一个 SYN 报文段。在发送过 SYN 报文段后,客户 TCP 进入了 SYN_SENT 状态。当客户 TCP 处在 SYN_SENT 状态时,它等待来自服务器 TCP 的对客户所发报文段进行确认且 SYN 比特被置为 1 的一个报文段。收到这样一个报文段之后,客户 TCP 进入 ESTABLISHED(已建立)状态。当处在 ESTABLISHED 状态时,TCP 客户就能发送和接收包含有效载荷数据(即应用层产生的数据)的 TCP 报文段了。

假设客户应用程序决定要关闭该连接。这引起客户 TCP 发送一个带有 FIN 比特被置为 1 的 TCP 报文段,并进入 FIN_WAIT_1 状态。当处在 FIN_WAIT_1 状态时,客户 TCP 等待一个来自服务器的带有确认的 TCP 报文段。当它收到该报文段时,客户 TCP 进入 FIN_WAIT_2 状态。当处在 FIN_WAIT_2 状态时,客户等待来自服务器的 FIN 比特被置为 1 的另一个报文段;当收到该报文段后,客户 TCP 对服务器的报文段进行确认,并进入 TIME_WAIT 状态。假定 ACK 丢失,TIME_WAIT 状态使 TCP 客户重传最后的确认报文。经过等待后,连接就正式关闭,客户端所有资源(包括端口号)将被释放。

服务器端 TCP 经历的典型的 TCP 状态序列:

在这里插入图片描述
假如一台主机接收了具有目的端口 80 的一个 TCP SYN 分组,但该主机在端口 80 不接受连接(即它不在端口 80 上运行 Web 服务器)。则该主机将向源发送一个特殊重置报文段。该 TCP 报文段将 RST 标志位置为 1.因此,当主机发送一个重置报文段时,它告诉该源 “我没有那个报文段的套接字。请不要再发送该报文段了”。

当一台主机接收一个 UDP 分组,它的目的端口与进行中的 UDP 套接字不匹配,该主机发送一个特殊的 ICMP 数据报。

5.6.1 SYN 洪泛攻击

在 TCP 三次握手中可用看到,服务器为了响应一个收到的 SYN,分配并初始化连接变量和缓存。然后服务器发送一个 SYNACK 进行响应,并等待来自客户的 ACK 报文。如果某客户不发送 ACK 来完成该三次握手的第三步,最终(通常在一分钟之后)服务器将终止该半开连接并回收资源。

这种 TCP 连接管理协议为经典的 DoS 攻击即 SYN 洪泛攻击提供了环境。在这种攻击中,攻击者发送大量的 TCP SYN 报文段,而不完成第三次握手的步骤。随着这种 SYN 报文段纷至沓来,服务器不断为这些半开连接分配资源(但从未使用),导致服务器的资源被消耗殆尽。

一种有效的防御系统,称为 SYN cookie,它们被部署在大多数主流操作系统中。SYN cookie 以下列方式工作:

  • 当服务器接收到一个 SYN 报文段时,它并不知道该报文段是来自一个合法的用户,还是一个 SYN 洪泛攻击的一部分。因此服务器不会为该报文段生成一个半开连接。相反,服务器生成一个初始 TCP 序列号,该序列号是 SYN 报文段的源和目的 IP 地址与端口号以及仅有该服务器知道的秘密数的一个复杂函数(散列函数)。这种精心制作的初始序列号被称为 “cookie”。服务器则发送具有这种特殊初始序列号的 SYNACK 分组。重要的是,服务器并不记忆该 cookie 或任何对应于 SYN 的其他状态信息
  • 如果客户是合法的,则它将返回一个 ACK 报文段。当服务器收到该 ACK,需要验证该 ACK 是与前面发送的某些 SYN 相对应的。如果服务器没有维护有关 SYN 报文段的记忆,这是怎样完成的呢?正如你可能猜测的那样,它是借助于 cookie 来做到的。前面讲过对于一个合法的 ACK,在确认字段中的值等于在 SYNACK 字段(此时为 cookie 值)中的值加 1。服务器则将使用在 SYNACK 报文段中的源和目的地 IP 地址与端口号(它们与初始的 SYN 中的相同)以及秘密数运行相同的散列函数。如果该函数的结果加 1 与在客户的 SYNACK 中的确认(cookie)值相同的话,服务器认为该 ACK 对应于较早的 SYN 报文段,因此它是合法的。服务器则生成一个具有套接字的全开的连接。
  • 在另一方面,如果客户没有返回一个 ACK 报文段,则初始的 SYN 并没有对服务器产生危害,因为服务器没有为它分配任何资源。

六、拥塞控制原理

6.1 拥塞原因与代价

6.1.1 情况 1:两个发送方和一台具有无穷大缓存的路由器

拥塞情况 1:两条连接共享具有无限大缓存的单跳路由。

在这里插入图片描述
拥塞情况 1:吞吐量、时延与主机发送速率的函数关系。

在这里插入图片描述

6.1.2 情况 2:两个发送方和一台具有有限缓存的路由器

情况 2:(有重传的)两台主机与一台拥有有限缓存的路由器。

在这里插入图片描述
具有有限缓存时情况2的性能:

  • a)主机 A 能够以某种方式确定路由器中的缓存是否空闲,因而仅当缓存空闲时才发送一个分组。
  • b)发送方仅当在确认了一个分组已经丢失时才重传。
  • c)发送方也许会提前发生超时并重传在队列中已被推迟但还未丢失的分组。

在这里插入图片描述

6.1.3 情况 3:4 个发送方和具有有限缓存的多台路由器及多跳路径

在这里插入图片描述
具有有限缓存和多跳路径时的情况 3 性能:

在这里插入图片描述

6.2 拥塞控制方法

  • 端到端拥塞控制
    在端到端拥塞控制方法中,网络层没有为运输层拥塞控制提供显式支持。即使网络中存在拥塞,端系统也必须通过对网络行为的观察(如分组丢失与时延)来推断之。

  • 网络辅助的拥塞控制
    在网络辅助的拥塞控制中,路由器向发送方提供关于网络中拥塞状态的显式反馈信息。这种反馈可用简单地用一个比特来指示链路中的拥塞情况。

网络指示拥塞信息的两种反馈路径:

在这里插入图片描述
对于网络辅助的拥塞控制,拥塞信息从网络反馈到发送方通常用两种方式,如图所示。

直接反馈信息可以由网络路由器发给发送方。这种方式的通知通常采用了一种阻塞分组的形式。

更为通用的第二种形式的通知是,路由器标记或更新从发送方流向接收方的分组中的某个字段来指示拥塞的产生。一旦收到一个标记的分组后,接收方就会向发送方通知该网络拥塞指示。

七、TCP 拥塞控制

TCP 必须使用端到端拥塞控制而不是使网络辅助的拥塞控制,因为 IP 层不向端系统提供显式的网络拥塞反馈。

TCP 所采用的方法是让每一个发送方根据所感知到的网络拥塞程度来限制其能向连接发送流量的速率。

TCP 发送方如何限制向其连接发送流量

TCP 连接的每一端都是由一个接收缓存、一个发送缓存和几个变量(LastByteRead、rwnd 等)组成。运行在发送方的 TCP 拥塞控制机制跟踪一个额外的变量,即拥塞窗口。拥塞窗口表示为 cwnd,它对一个 TCP 发送方能向网络中发送流量的速率进行了限制。特别是,在一个发送方中未被确认的数据量不会超过 cwnd 与 rwnd 中的最小值,即

LastByteSent - LastByteAcked <= min { cwnd, rwnd }

TCP 控制报文发送速率的指导性原则

  • 一个丢失的报文段表意味着拥塞,因此当丢失报文段时应当降低 TCP 发送方的速率。
  • 一个确认报文段指示该网络正在向接收方交付发送方的报文段,因此,当对先前未确认报文段的确认到达时,能够增加发送方的速率。
  • 带宽探测。给定 ACK 指示源到目的地路径无拥塞,而丢包事件指示路径拥塞,TCP 调节其传输速率的策略是增加其速率以响应到达的 ACK,除非出现丢包事件,此时才减小传输速率。

7.1 TCP 拥塞控制算法

TCP 拥塞控制的 FSM 描述:

在这里插入图片描述

7.1.1 慢启动

慢启动状态,cwnd 的值以 1 个 MSS 开始并且每当传输的报文段首次被确认就增加 1 个 MSS。这一过程每过一个 RTT,发送速率就翻番。因此,TCP 发送速率起始慢,但在慢启动阶段以指数增长。

在这里插入图片描述

慢启动结束的第一种方式是,如果存在一个由超时指示的丢包事件(即拥塞),TCP 发送方将 cwnd 设置为 1 并重新开始慢启动过程。它还将第二个状态变量的值 ssthresh(慢启动阈值)设置为 cwnd/2,

慢启动结束的第二种方式是直接与 ssthresh 的值相关联。当 cwnd 的值等于 ssthresh 时,结束慢启动并且 TCP 转移到拥塞避免模式。

最后一种结束慢启动的方式是,如果检测到 3 个冗余 ACK,这时 TCP 执行一种快速重传并进入快速恢复状态。

7.1.2 拥塞避免

一旦进入拥塞避免状态,cwnd 的值大约是上次遇到拥塞时的一半,因此,TCP 无法每过一个 RTT 再将 cwnd 的值翻番,而是采用了一种较为保守的方式,每个 RTT 只将 cwnd 的值增加一个 MSS。

当出现超时时,TCP 的拥塞避免算法行为相同。与慢启动的情况一样,cwnd 的值被设置为 1 个 MSS,当丢包事件出现时,ssthresh 的值被更新为 cwnd 值的一半。

丢包事件也能由一个 3 个冗余 ACK 事件触发。在这种情况下,网络继续从发送方向向接收方交付报文段。TCP 将 cwnd 的值减半,并且当收到 3 个冗余的 ACK,将 ssthresh 的值记录为 cwnd 的值的一半。接下来进入快速恢复状态。

7.1.3 快速恢复

在快速恢复中,对于引起 TCP 进入快速恢复状态的缺失报文段,对收到的每个冗余 ACK,cwnd 的值增加一个 MSS。最终,当对丢失报文段的一个 ACK 到达时,TCP 在降低 cwnd 后进入拥塞避免状态。当丢包事件出现时,cwnd 的值被设置为 1 个 MSS,并且 ssthresh 的值设置为 cwnd 值的一半。

TCP 拥塞窗口的演化:

在这里插入图片描述

  • TCP Tahoe:TCP 早期版本。不管是发生超时指示的丢包事件,还是发生 3 个冗余 ACK 指示的丢包事件,都无条件地将其拥塞窗口减至 1 个 MSS,并进入慢启动阶段。
  • TCP Reno:综合了快速恢复。

7.1.4 TCP 拥塞控制:回顾

忽略一条连接开始时初始的慢启动阶段,假定丢包由 3 个冗余的 ACK 而不是超时指示,TCP 的拥塞控制是:每个 RTT 内 cwnd 线性(加性)增加 1MSS,然后出现 3 个冗余 ACK 事件时 cwnd 减半(乘性减)。因此,TCP 拥塞控制常常被称为加性增、乘性减(AIMD)拥塞控制方式。

在这里插入图片描述

7.2 公平性

考虑 K 条 TCP 连接,每条都有不同的端到端路径,但是都经过一段传输速率为 R bps 的瓶颈链路。如果每条连接的平均传输速率接近 R/K,即每条连接都得到相同份额的链路带宽,则认为该拥塞控制机制是公平的。

两条 TCP 连接共享同一条瓶颈链路:

在这里插入图片描述

TCP 连接 1 和连接 2 实现的吞吐量:

在这里插入图片描述

7.3 明确拥塞通告:网络辅助拥塞控制

一个 TCP 发送方不会收到来自网络层的明确拥塞指示,而是通过观察分组丢失来推断拥塞。最近,对于 IP 和 TCP 的扩展方案 [ RFC 3168 ] 已经提出并已经实现和部署,该方案允许网络明确向 TCP 发送方和接收方发出拥塞信号。这种形式的网络辅助拥塞控制称为明确拥塞通告(ECN)。如图所示,涉及了 TCP 和 IP 协议。

明确拥塞通告:网络辅助拥塞控制

在这里插入图片描述
在网络层,IP 数据报首部的服务类型字段中的两个比特被用于 ECN。路由器所使用的一种 ECN 比特设置指示该路由器正在历经拥塞。该拥塞指示则由被标记的 IP 数据报所携带,送给目的主机,再由目的主机通知发送主机。

当接收主机中的 TCP 通过一个接收到的数据报收到了一个 ECN 拥塞指示时,接收主机中的 TCP 通过在接收方到发送方的 TCP ACK 报文段中设置 ECE(明确拥塞通告回显)比特,通知发送主机中的 TCP 收到拥塞指示。

接下来,TCP 发送方通过减半拥塞窗口对一个具有 ECE 拥塞指示的 ACK 做出反应,并且在下一个传输的 TCP 发送方到接收方的报文段首部中对 CWR(拥塞窗口缩减)比特进行设置。

✨一个值得尝试的GPT变现小项目✨

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值