计算机网络自顶向下方法::运输层

概述和运输层服务

  • 运输层协议为运行在不同主机上的应用进程之间提供了逻辑通信。应用进程使用运输层提供的逻辑通信功能彼此发送报文,而无须考虑承载这些报文的物理基础设施的细节。
  • 运输层协议是在端系统中而不是在路由器中实现的。在发送端,运输层将从发送应用程序进程接收到的报文转换成运输层分组,用因特网术语来讲该分组称为运输层报文段(segment)。在接收端,网络层从数据报中提取运输层报文段,并将该报文段向上交给运输层 。运输层则处理接收到的报文段,使该报文段中的数据为接收应用进程使用。
  • 网络应用程序可以使用多种的运输层协议。例如,因特网有两种协议,即 TCP 和 UDP。每种协议都能为调用的应用程序提供一组不同的运输层服务。
  • 运输层和网络层的关系
    • 在协议栈中,运输层刚好位于网络层之上。网络层提供了主机之间的逻辑通信,而运输层为运行在不同主机上的进程之间提供了逻辑通信
    • 计算机网络中可以安排多种运输层协议,每种协议为应用程序提供不同的服务模型。
    • 运输协议能够提供的服务常常受制于底层网络层协议的服务模型。如果网络层协议无法为主机之间发送的运输层报文段提供时延或带宽保证的话,运输层协议也就无法为进程之间发送的应用程序报文提供时延或带宽保证。
    • 即使底层网络协议不能在网络层提供相应的服务,运输层协议也能提供某些服务。例如可靠运输。
  • 因特网运输层概述
    • UDP:它为调用它的应用程序提供了一种不可靠、无连接的服务
    • TCP:它为调用它的应用程序提供了一种可靠的、面向连接的服务
    • 当设计一个网络应用程序时,该应用程序的开发人员必须指定使用这两种运输协议中的一种
    • 因特网网络层协议有一个名字叫 IP, 即网际协议。IP 为主机之间提供了逻辑通信。IP 的服务模型是尽力而为交付服务,是不可靠的
    • 我们总结一下 UDP 和 TCP 所提供的服务模型。UDP 和 TCP 最基本的责任是,将两个端系统间 IP 的交付服务扩展为运行在端系统上的两个进程之间的交付服务。将主机间交付扩展到进程间交付被称为运输层的多路复用 (transport-layer multiplexing) 与 多路分解 (demultiplexing)
    • 进程到进程的数据交付和差错检查是两种最低限度的运输层服务,也就是 UDP 所提供的服务
    • TCP 额外供了可靠数据运输和拥塞控制

多路复用和多路分解

  • 一个进程有一个或多个套接字,它相当于从网络向进程传递数据和从进程向网络传递数据的门户。在接收主机中的运输层实际上并没有直接将数据交付给进程,而是将数据交给了一个中间的套接字。由于在任一时刻,在接收主机上可能有不止一个套接字,所以每个套接字都有唯一的标识符。标识符的格式取决于它是 UDP 还是 TCP 套接字。
  • 主机为了将一个到达的运输层报文段定向到适当的套接字,每个运输层报文段中具有几个字段。在接收端,运输层检查这些字段,标识出接收套接字,进而将报文段定向到该套接字。将运输层报文段中的数据交付到正确的套接字的工作称为多路分解(demulti plexing)。在源主机从不同套接字中收集数据块,并为每个数据块封装上首部信息(这将在以后用于分解)从而生成报文段,然后将报文段传递到网络层,所有这些工作称为多路复用(multiplexing)
  • 运输层多路复用要求
    • 套接字有唯一标识
    • 每个报文段有特殊字段来指示该报文段所要交付到的套接字
    • 这些特殊字段是源端口号字段和目的端口号字段
  • 在主机上的每个套接字能够分配一个端口号,当报文段到达主机时,运输层检查报文段中的目的端口号,并将其定向到相应的套接字。然后报文段中的数据通过套接字进入其所连接的进程
  • 无连接的多路复用与多路分解
    • 一个 UDP 套接字是由一个二元组全面标识的,该二元组包含一个目的 IP 地址和一个目的端口号。因此,如果两个 UDP 报文段有不同的源 IP 地址和/或源端口号,但具有相同的目的 IP 地址和目的端口号,那么这两个报文段将通过相同的目的套接字被定向到相同的目的进程。
  • 面向连接的多路复用与多路分解
    • TCP 套接字是由一个四元组(源 IP 地址,源端口号,目的 IP 地址,目的端口号)来标识的
    • 两个具有不同源 IP 地址或源端口号的到达 TCP 报文段将被定向到两个不同的套接字
  • Web 服务器与 TCP
    • 如果客户与服务器使用持续 HTTP,则在整条连接持续期间 ,客户与服务器之间经由同一个服务器套接字交换 HTTP 报文 。然而,如果客户与服务器使用非持续 HTTP, 则对每一对请求/响应都创建一个新的 TCP 连接并在随后关闭、因此对每一对请求/响应创建一个新的套接字并在随后关闭。这种套接字的频繁创建和关闭会严重地影响一个繁忙的 Web 服务器的性能

无连接运输:UDP

  • UDP 只是做了运输协议能够做的最少工作。除了复用/分解功能及少量的差错检测外,它几乎没有对 IP 增加别的东西。
  • 使用 UDP 时,在发送报文段之前,发送方和接收方的运输层实体之间没有握手
  • 使用 UDP 的理由
    • 关于发送什么数据以及何时发送的应用层控制更为精细
    • 无须连接建立
    • 无连接状态
    • 分组首部开销小
  • UDP 中缺乏拥塞控制能够导致 UDP 发送方和接收方之间的高丢包率,并挤垮了 TCP 会话,这是一个潜在的严重问题。很多研究人员已经提出了一些新的机制,使得 UDP 执行自适应的拥塞控制
  • 使用 UDP 的应用是可能实现可靠数据传输的。这可通过在应用程序自身中建立可靠性机制来完成。例如 Google 的 QUIC。
  • UDP 报文段结构
    • 源端口,发送方的端口号
    • 目的端口,接收方的端口号
    • 报文长度,即整个 UDP 报文的长度,包括头部和数据,单位为字节
    • 检验和。
    • 应用数据,也就是报文
  • UDP 检验和
    • 检验和用千确定当 UDP 报文段从源到达目的地移动时,其中的比特是否发生了改变
    • 发送方的 UDP 对报文段中的所有 16 比特字的和进行反码运算,求和时遇到的任何溢出都被回卷。 得到的结果被放在 UDP 报文段中的检验和字段,在接收方,全部的 4 个 16 比特字(包括检验和)没有引入差错 ,则显然在接收方处该和将是 1111111111111111
    • UDP 提供差错检测是因为不能保证源和目的之间的所有链路都提供差错检测;这就是说,也许这些链路中的一条可能使用没有差错检测的协议

可靠数据传输原理

  • 构造可靠数据传输协议
    • 经完全可靠信道的可靠数据传输: rdt1.0
      • 首先,我们考虑最简单的情况,即底层信道是完全可靠的。我们称该协议为 rdt1.0,该协议本身是简单的。在这个简单的协议中,一个单元数据与一个分组没差别。而且,所有分组是从发送方流向接收方;有了完全可靠的信道,接收端就不需要提供任何反馈信息给发送方,因为不必担心出现差错!注意到我们也已经假定了接收方接收数据的速率能够与发送方发送数据的速率一样快。因此,接收方没有必要请求发送方慢一点!
    • 经具有比特差错信道的可靠数据传输:rdt2.0
      • 底层信道更为实际的模型是分组中的比特可能受损的模型。在分组的传输、传播或缓存的过程中,这种比特差错通常会出现在网络的物理部件中,我们眼下还将继续假定所有发送的分组(虽然有些比特可能受损)将按其发送的顺序被接收。
      • 控制报文使得接收方可以让发送方知道哪些内容被正确接收,哪些内容接收有误并因此需要重复。在计算机网络环境中,基于这样重传机制的可靠数据传输协议称为自动重传请求(Automatic Repeat Request,ARQ)协议。
        • 差错检测:首先,需要一种机制以使接收方检测到何时出现了比特差错
        • 接收方反馈:rdt2.0 协议将从接收方向发送方反馈是否接受的分组。
        • 重传:接收方收到有差错的分组时,发送方将重传该分组文
      • 当发送方处于等待 ACK 或 NAK 的状态时,它不能从上层获得更多的数据,仅当接收到 ACK 并离开该状态时才能发生这样的事件,因此,发送方将不会发送一块新数据,除非发送方确信接收方已正确接收当前分组。由于这种行为,rdt2.0 这样的协议被称为停等(stop-and-wait)协议。
      • 考虑受损 ACK 和 NAK 的 3 种可能性
        • 增加确认机制,会陷入无尽的确认,不可行
        • 增加足够的检验和比特,使发送方不仅可以检测差错,还可恢复差错
        • 当发送方收到含糊不清的 ACK 或 NAK 分组时,只需重传当前数据分组即可。然而,这种方法在发送方到接收方的信道中引入了冗余分组 (duplicate packet)。冗余分组的根本困难在于接收方不知道它上次所发送的 ACK 或 NAK 是否被发送方正确地收到。因此它无法事先知道接收到的分组是新的还是一次重传!
      • 解决这个新问题的一个简单方法是在数据分组中添加一新字段,让发送方对其数据分组编号,即将发送数据分组的序号放在该字段。于是,接收方只需要检查序号即可确定收到的分组是否一次重传。对于停等协议这种简单情况,1 比特序号就足够了,因为它可让接收方知道发送方是否正在重传前一个发送分组,或是一个新分组。
      • 协议 rdt2.1 使用了从接收方到发送方的肯定确认和否定确认。当接收到失序的分组时,接收方对所接收的分组发送一个肯定确认。如果收到受损的分组,则接收方将发送一个否定确认。如果不发送 NAK, 而是对上次正确接收的分组发送一个 ACK, 我们也能实现与 NAK 一样的效果。发送方接收到对同一个分组的两个 ACK,就知道接收方没有正确接收到跟在被确认两次的分组后面的分组,rdt2.2 是在有比特差错信道上实现的一个无 NAK 的可靠数据传输协议
    • 经具有比特差错的丢包信道的可靠数据传输:rdt3.0
      • 协议现在必须处理另外两个关注的问题:怎样检测丢包以及发生丢包后该做些什么
      • 发送方负责检测和恢复丢包工作
      • 判断丢失:发送方传输一个数据分组,该分组或者接收方对该分组的 ACK 发生了丢失。在这两种情况下,发送方都收不到应当到来的接收方的响应。如果发送方愿意等待足够长的时间以便确定分组已丢失,则它只需重传该数据分组即可。
      • 决定等待时长:即发送方与接收方之间的一个往返时延(可能会包括在中间路由器的缓冲时延)加上接收方处理一个分组所需的时间。为了实现基于时间的重传机制,需要一个倒计数定时器,在一个给定的时间掀过期后,可中断发送方。因此,发送方需要能做到:每次发送一个分组(包括第一次分组和重传分组)时,便启动一个定时器;响应定时器中断;终止定时器
    • 现在我们归纳一下数据传输协议的要点。在检验和、序号、定时器、肯定和否定确认分组这些技术中,每种机制都在协议的运行中起到了必不可少的作用。至此,我们得到了一个可靠数据传输协议!
  • 流水线可靠数据传输协议
    • rtd3.0 有个停等协议影响性能,存在信道利用率低的问题。
    • 这种特殊的性能问题的一个简单解决方法是:不以停等方式运行,允许发送方发送多个分组而无须等待确认,因为许多从发送方向接收方输送,的分组可以被看成是填充到一条流水线中,故这种技术被称为流水线
    • 流水线协议对可靠数据传输协议带来的影响
      • 增加序列号范围
      • 发送方和接收方需要缓存多个分组
      • 所需序号范围和对缓冲的要求取决于数据传输协议如何处理丢失、损坏及延时过大的分组。解决流水线的差错恢复有两种基本方法是:回退 N 步 (Go-Back-N, GBN) 和选择重传 (Selective Repeat, SR) 。
  • 回退 N 步
    • 那些已被发送但还未被确认的分组的许可序号范围可以被看成是一个在序号范围内长度为 N 的窗口,随着协议的运行,该窗口在序号空间向前滑动。因此,N 常被称为窗口长度 (window size),GBN 协议也常被称为滑动窗口协议 (sliding-window protocol)。
    • GNB 发送方需要响应三种类型的事件
      • 上层的调用:当上层调用发送函数时,如果队列满了就不发送。
      • 收到一个 ACK:对收到的序号 n 和 n 以前的分组全部确认
      • 超时事件:如果出现超时,发送方重传所有已发送但还未被确认过的分组
    • 接收方如果一个需要为 n 的分组被正确按序接受,则接收方为分组 n 发送一个 ACK, 并将该分组中的数据部分交付到上层。在所有其他情况下,接收方丢弃该分组,并为最近按序接收的分组重新发送 ACK。因为接收方需要按序交付分组给上层。
  • 选择重传
    • 选择重传 (SR) 协议通过让发送方仅重传那些它怀疑在接收方出错(即丢失或受损)的分组而避免了不必要的重传。这种个别的、按需的重传要求接收方逐个地确认正确接收的分组。再次用窗口长度 N 来限制流水线中未完成 、未被确认的分组数。然 而,与 GBN 不同的是,发送方已经收到了对窗口中某些分组的 ACK。
    • SR 接收方将确认一个正确接收的分组而不管其是否按序。失序的分组将被缓存直到所有丢失分组(即序号更小的分组 )皆被收到为止,这时才可以将一批分组按序交付给上层 。
    • 发送方的事件
      • 从上层收到数据。当从上层接收到数据后,SR 发送方检查下一个可用于该分组的序号。如果序号位于发送方的窗口内,则将数据打包并发送;否则就像在 GBN 中一样,要么将数据缓存,要么将其返回给上层以便以后传输。
      • 超时。定时器再次被用来防止丢失分组。然而 ,现在每个分组必须拥有其自己的逻辑定时器,因为超时发生后只能发送一个分组。可以使用单个硬件定时楛模拟多个逻辑定时器的操作。
      • 收到 ACK。如果收到 ACK, 倘若该分组序号在窗口内,则 SR 发送方将那个被确认的分组标记为已接收。如果该分组的序号等于 send_base, 则窗口基序号向前移动到具有最小序号的未确认分组处。如果窗口移动了并且有序号落在窗口内的未发送分组,则发送这些分组。
    • 接收方的事件
      • 序号在[rev_base,rcv_base + N - 1]内的分组被正确接收。在此情况下,收到的分组落在接收方的窗口内,一个选择 ACK 被回送给发送方。如果该分组以前没收到过,则缓存该分组。如果该分组的序号等于接收窗口的基序号,则该分组以及以前缓存的序号连续的分组交付给上层。然后,接收窗口按向前移动分组的编号向上交付这些分组。
      • 序号在 [ rcv_base - N, rcv_base - 1] 内的分组被正确收到。在此情况下,必须产生一个 ACK, 是接收方以前已确认过的分组 。
      • 其他情况。忽略该分组 。
    • 对于哪些分组已经被正确接收,哪些没有,发送方和接收方并不总是能看到相同的结果。对 SR 协议而言,这就意味着发送方和接收方的窗口并不总是一致。

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

  • 检验和;用于检测在一个传输分组中的比特错误
  • 定时器:用于超时/重传一个分组,可能因为该分组〈或其 ACK) 在信道中丢失了。由于当一个分组延时但未丢失〈过早超时) ,或当一个分组已被接收方收到但从接收方到发送方的 ACK 丢失时,可能产生超时事件,所以接收方可能会收到一个分组的多个冗余副本
  • 序号:用于为从发送方流向接收方的数据分组按顺序编号。所接收分组的序号间的空隙可使接收方检测出丢失的分组。具有相同序号的分组可使接收方检测出一个分组的冗余副本
  • 确认:接收方用于告诉发送方一个分组或一组分组已被正确地接收到了。确认报文通常携带着被确认的分组或多个分组的序号。确认可以是逐个的或累积的,这取决于协议
  • 否定确认:接收方用于告诉发送方某个分组未被正确地接收。否定确认报文通常据带着未被正确接收的分组的序号
  • 窗口、流水线:发送方也许被限制仅发送那些序号落在一个指定范围内的分组。通过允许一次发送多个分组但未被确认,发送方的利用率可在停等操作模式的基础上得到增加。我们很快将会看到,窗口长度可根据接收方接收和缓存报文的能力、网络中的拥塞程度或两者情况来进行设置

面向连接的运输:TCP

  • TCP 是因特网运输层的面向连接的可靠的运输协议
  • TCP 连接
    • TCP 被称为是面向连接的(connection-oriented) ,这是因为在一个应用进程可以开始向另一个应用进程发送数据之前,这两个进程必须先相互"握手”,即它们必须相互发送某些预备报文段,以建立确保数据传输的参数。作为 TCP 连接建立的一部分,连接的双方都将初始化与 TCP 连接相关的许多 TCP 状态变量
    • 这种 TCP “连接”不是一条像在电路交换网络中的端到端 TOM 或 FDM 电路。相反,该“连接”是一条逻辑连接,其共同状态仅保留在两个通信端系统的 TCP 程序中,而不在中间的网络元素中运行,所以中间的网络元素不会维持 TCP 连接状态
    • TCP 连接也总是点对点(point-to-point)的,即在单个发送方与单个接收方之间的连接,无法实现多播
    • 三次握手
      • 客户首先发送一个特殊的 TCP 报文段
      • 服务器用另一个特殊的 TCP 报文段来响应
      • 客户再用第三个特殊报文段作为响应
      • 前两个报文段不承载“有效载荷",也就是不包含应用层数据;而第三个报文段可以承载有效载荷
    • 最大传输单元 MTU
    • 最大报文段长度 MSS(Maximum Segment Size),在报文段里应用层数据的最大长度,而不是指包括首部的 TCP 报文段的最大长度
    • TCP 为每块客户数据配上一个 TCP 首部,从而形成多个 TCP 报文段 (TCP segment)。这些报文段被下传给网络层,网络层将其分别封装在网络层 IP 数据报中。然后这些 IP 数据报被发送到网络中。当 TCP 在另一端接收到一个报文段后,该报文段的数据就被放入该 TCP 连接的接收缓存中。应用程序从此缓存中读取数据流。该连接的每一端都有各自的发送缓存和接收缓存
  • TCP 报文段结构
    • TCP 报文段由首部字段和一个数据字段组成。数据字段包含一块应用数据。
    • 报文段结构
      • 首部包括源端口号和目的端口号,它被用于多路复用/分解来自或送到上层应用的数据 。TCP 首部也包括检验和字段
      • 32 比特的序号字段和 32 比特的确认号字段。这些字段被 TCP 发送方和接收方用来实现可靠数据传输服务
      • 16 比特的接收窗口字段,该字段用于流量控制。该字段用于指示接收方愿意接受的字节数量。
      • 4 比特的首部长度字段。该字段指示了以 32 比特的字为单位的 TCP 首部长度。由于 TCP 选项字段的原因,TCP 首部的长度是可变的。
      • 可选与变长的选项字段,该字段用于发送方与接收方协商最大报文段长度,或在高速网络环境下用作窗口调节因子时使用。
      • 6 比特的标志字段,ACK 比特用于指示确认字段中的值是有效的,即该报文段包括一个对已被成功接收报文段的确认。RST、SYN 和 FIN 比特用于连接建立和拆除,在明确拥塞通告中使用了 CWR 和 ECE 比特,URG 比特用来指示报文段里存在着被发送端的上层实体置为"紧急"的数据
      • 紧急数据指针字段,当紧急数据存在并给出指向紧急数据尾指针的时候,TCP 必须通知接收端的上层实体
    • 序号和确认号
      • TCP 把数据看成一个无结构的、有序的字节流。因为序号是建立在传送的字节流之上,而不是建立在传送的报文段的序列之上。一个报文段的序号(sequence number for a segment)因此是该报文段首字节的字节流编号。
      • 主机 A 填充进报文段的确认号是主机 A 期望从主机 B 收到的下一字节的序号。
      • 假设主机 A 已收到一个来自主机 B 的包含字节 0 ~ 535 的报文段,以及另一个包含字节 900 ~ 1000 的报文段。由于某种原因,主机 A 还没有收到字节 536 ~ 899 的报文段。在这个例子中,主机 A 为了重新构建主机 B 的数据流,仍在等待字节 536 (和其后的字节)。因此,A 到 B 的下一个报文段将在确认号字段中包含 536。因为 TCP 只确认该流中至第一个丢失字节为止的字节,所以 TCP 被称为提供累积确认 (cumulative acknowledgment)
      • RFC 协议没有规定接收方收到失序的报文段要怎么处理
        • 有两种基本的选择:
          • 接收方立即丢弃失序报文段
          • 接收方保留失序的字节,并等待缺少的字节以填补该间隔
        • 后一种对网络带宽而言比较有效,是实践中采用的方案
  • 往返时间的估计与超时
    • 估计往返时间
      • 在任意时刻,仅为一个已发送的但目前尚未被确认的报文段估计 SampleRTT, 从而产生一个接近每个 RTT 的新 SampleRTT 值。TCP 决不为已被重传的报文段计算 SampleRTT; 它仅为传输一次的报文段测量 SampleRTT
      • 为了估计一个典型的 RTT,自然要采取某种对 SampleRTT 取平均的办法。TCP 维持一个 SampleRTT 均值(称为 EstimatedRTT)。一旦获得一个新 SampleRTT 时,TCP 就会根据下列公式来更新 Esti­matedRTT:
        • EstimatedRTT = (1 - a ) * EstimatedRTT + a * SampleRTI
      • 这个加权平均对最近的样本赋予的权值要大于对旧样本赋予的权值。这是很自然的,因为越近的样本越能更好地反映网络的当前拥塞情况。从统计学观点讲,这种平均被称为指数加权移动平均(Exponential Weighted Moving Average, EWMA) 。
      • 除了估算 RTT 外,测量 RTT 变化也是有价值的。DevRTT, 用于估算 SampleRTT 一般会偏离 EstimatedRTT 的程度:
        • DevRTT = (1 -b) * DevRTT + |SampleRTT - EstimatedRTT|
    • 设置和管理重传超时间隔
      • 超时间隔应该大于等于 EstimatedRTT,否则,将造成不必要的重传。但是超时间隔也不应该比 EstimatedRTT 大太多,否则当报文段丢失时,TCP 不能很快地重传该报文段,导致数据传输时延大。因此要求将超时间隔设为 EstimatedRTT 加上一定余量。
        • TimeoutTnterval = EstimatedRTT + 4 * DevRTT
  • 可靠数据传输
    • 因特网的网络层服务(IP 服务)是不可靠的。 IP 不保证数据报的交付,不保证数据报的按序交付,也不保证数据报中数据的完整性。对于 IP 服务,数据报能够溢出路由器缓存而永远不能到达目的地,数据报也可能是乱序到达,而且数据报中的比特可能损坏
    • TCP 的可靠数据传输服务确保一个进程从其接收缓存中读出的数据流是无损坏、无间隙、非冗余和按序的数据流;即该字节流与连接的另一方端系统发送出的字节流是完全相同
    • TCP 发送方有 3 个与发送和重传有关的主要事件:
      • 从上层应用程序接收数据
        • TCP 从应用程序接收数据,将数据封装在一个报文段中,并把该报文段交给 IP,每一个报文段都包含一个序号,这个序号就是该报文段第一个数据字节的字节流编号。当报文段被传给 IP 时,TCP 就启动定时器,该定时器的过期间隔是 TimeoutInterval
      • 定时器超时
        • TCP 通过重传引起超时的报文段来响应超时事件。然后 TCP 重启定时器。
      • 收到 ACK
        • 当该事件发生时,TCP 将 ACK 的值 y 与它的变量 SendBase 进行比较 TCP 状态变量 SendBase 是最早未被确认的字节的序号。如果 y > SendBase, 则该 ACK 是在确认一个或多个先前未被确认的报文段。因此发送方更新它的 SendBase 变量;如果当前有未被确认的报文段,TCP 还要重新启动定时器。
    • 超时间隔加倍:每当超时事件发生时,TCP 重传具有最小序号的还未被确认的报文段。只是每次 TCP 重传时都会将下一次的超时间隔设为先前值的两倍,而不是用从 EstimaledRTT 和 DevRTT 推算出的值。这种修改提供了一个形式受限的拥塞控制 。定时器过期很可能是由网络拥塞引起的,即太多的分组到达源与目的地之间路径上的一台或多台路由器的队列中,造成分组丢失或长时间的排队时延。在拥塞的时候,如果源持续重传分组,会使拥塞更加严重。相反,TCP 使用更文雅的方式 ,每个发送方的重传都是经过越来越长的时间间隔后进行的
    • 快速重传:因为发送方经常一个接一个地发送大量的报文段,如果一个报文段丢失,就很可能引起许多一个接一个的冗余 ACK。如果 TCP 发送方接收到对相同数据的 3 个冗余 ACK, 它把这当作一种指示,说明跟在这个已被确认过 3 次的报文段之后的报文段已经丢失。即在该报文段的定时器过期之前重传丢失的报文段。
    • GBN 还是 SR:很多 TCP 的实现融合了 GBN 和 SR
  • 流量控制
    • TCP 为它的应用程序提供了流量控制服务 (flow-control service) 以消除发送方使接收方缓存溢出的可能性。流量控制因此是一个速度匹配服务,即发送方的发送速率与接收方应用程序的读取速率相匹配
    • TCP 发送方也可能因为 IP 网络的拥塞而被遏制;这种形式的发送方的控制被称为拥塞控制
    • TCP 通过让发送方维护 一个称为接收窗口 (receive window) 的变量来提供流量控制,接收窗口用于给发送方一个指示——该接收方还有多少可用的缓存空间。由于该空间是随着时间变化的,所以 rwnd 是动态的。接收方通过把当前的 rwnd 值放入它发给发送方的报文段接收窗口字段中,通知主机 A 它在该连接的缓存中还有多少可用空间。
    • 当接收方接收窗口为 0 时,主机 A 继续发送只有一个字节数据的报文段。这些报文段将会被接收方确认。最终缓存将开始清空,并且确认报文里将包含一个非 0 的 rwnd 值。
    • UDP 并不提供流量控制,报文段由于缓存溢出可能在接收方丢失
  • TCP 连接管理
    • 建立连接
      • 笫一步:客户端的 TCP 首先向服务器端的 TCP 发送一个特殊的 TCP 报文段。该报文段中不包含应用层数据。但是在报文段的首部中的一个标志位(即 SYN 比特)被置为 1。因此,这个特殊报文段被称为 SYN 报文段。另外,客户会随机地选择一个初始序号 (client_isn), 并将此编号放置于该起始的 TCP SYN 报文段的序号字段中。 该报文段会被封装在一个 IP 数据报中,并发送给服务器。为了避免某些安全性攻击,在适当地随机化选择 clienl_isn 方面有着不少有趣的研究
      • 第二步:一旦包含 TCP SYN 报文段的 IP 数据报到达服务器主机,服务器会从该数据报中提取出 TCP SYN 报文段,为该 TCP 连接分配 TCP 缓存和变量,并向该客户 TCP 发送允许连接的报文段。这个允许连接的报文段也不包含应用层数据。但是,在报文段的首部却包含 3 个重要的信息。
        • 首先,SYN 比特被置为 1。
        • 其次该 TCP 报文段首部的确认号字段被置为 client_isn + 1。
        • 最后,服务器选择自己的初始序号 (server_isn) , 并将其放置到 TCP 报文段首部的序号字段中。
      • 第三步: 在收到 SYNACK 报文段后,客户也要给该连接分配缓存和变量。客户主机则向服务器发送另外一个报文段;这最后一个报文段对服务器的允许连接的报文段进行了确认(该客户通过将值 server_isn + 1 放置到 TCP 报文段首部的确认字 段中来完成此项工作)。 因为连接巳经建立了,所以该 SYN 比特被置为 0。 该三次握手的第三个阶段可以在报文段负载中携带客户到服务器的数据。
    • 结束连接
      • 客户应用进程发出一个关闭连接命令。这会引起客户 TCP 向服务器进程发送一个特殊的 TCP 报文段。这个特殊的报文段让其首部中的一个标志位即 FIN 比特被设置为 1。当服务器接收到该报文段后,就向发送方回送一个确认报文段。然后,服务器发送它自己的终止报文段,其 FIN 比特被置为 1。最后,该客户对这个服务器的终止报文段进行确认。此时,在两台主机上用于该连接的所有资源都被释放了。

拥塞控制原理

  • 拥塞原因和代价
    • 两个发送方和一台具有无穷大缓存的路由器
      • 当分组的到达速率接近链路容量时,分组经历巨大的排队时延。
    • 两个发送方和一台具有有限缓存的路由器
      • 即发送方必须执行重传以补偿因为缓存溢出而丢弃(丢失)的分组
      • 发送方在遇到大时延时所进行的不必要重传会引起路由器利用其链路带宽来转发不必要的分组副本
    • 4 个发送方和具有有限缓存的多台路由器及多跳路径
      • 当一个分组沿一条路径被丢弃时,每个上游路由器用于转发该分组到丢弃该分组而使用的传输容量最终被浪费掉了
  • 拥塞控制方法
    • 端到端拥塞控制:TCP 采用端到端的方法解决拥塞控制,因为 IP 层不会向端系统提供有关网络拥塞的反馈信息。TCP 报文段的丢失(通过超时或 3 次冗余确认而得知)被认为是网络拥塞的一个迹象, TCP 会相应地减小其窗口长度。
    • 网络辅助的拥塞控制:在网络辅助的拥塞控制中,路由器向发送方提供关于网络中拥塞状态的显式反馈信息。这种反馈可以简单地用一个比特来指示链路中的拥塞情况。
      • 直接反馈信息可以由网络路由器发给发送方这种方式的通知通常采用了一种阻塞分组 (choke packet)的形式
      • 更为通用的第二种形式的通知是,路由器标记或更新从发送方流向接收方的分组中的某个字段来指示拥塞的产生一旦收到一个标记的分组后,接收方就会向发送方通知该网络拥塞指示:注意到后一种形式的通知至少要经过一个完整的往返时间。

TCP 拥塞控制

  • 慢启动
    • 过程
      • 当一条 TCP 连接开始时,cwnd 的值通常初始置为一个 MSS 的较小值
      • 在慢启动(slow-start)状态,cwnd 的值以 1 个 MSS 开始并且每当传输的报文段首次被确认就增加 1 个 MSS。
      • TCP 向网络发送第一个报文段并等待一个确认。当该确认到达时,TCP 发送方将拥塞窗口增加一个 MSS, 并发送出两个最大长度的报文段。
      • 这两个报文段被确认,则发送方对每个确认报文段将拥塞窗口增加一个 MSS, 使得拥塞窗口变为 4 个 MSS, 并这样下去 。这一过程每过一个 RTT, 发送速率就翻番。因此,TCP 发送速率起始慢,但在慢启动阶段以指数增长。
    • 何时结束增长
      • 如果存在一个由超时指示的丢包事件,TCP 发送方将 cwnd 设置为 1 并重新开始慢启动过程。它还将第二个状态变量的值 ssthresh 设置为 cwnd/2, 即当检测到拥塞时将 ssthresh 置为拥塞窗口值的 一半
      • 当检测到拥塞时 ssthresh 设为 cwnd 的值一半,当到达或超过 ssthresh 的值时,继续使 cwnd 翻番可能有些鲁莽。因此,当 cwnd 的值等于 sstbresh 时,结束慢启动并且 TCP 转移到拥塞避免模式。我们将会看到,当进入拥塞避免模式时,TCP 更为谨慎地增加 cwnd。
      • 如果检测到 3 个冗余 ACK, 这时 TCP 执行一种快速重传并进入快速恢复状态。
  • 拥塞避免
    • 当发生拥塞时,cwnd 将为原来的一般,后续的每个 RTT 只将 cwnd 的值增加一个 MSS
    • TCP 对这种丢包事件的行为,相比 于超时指示的丢包,应当不那么剧烈:TCP 将 cwnd 的值减半, 并且当收到 3 个冗余的 ACK, 将 ssthresh 的值记录为 cwnd 的值的一半。接下来进入快速恢复状态。
  • 快速恢复
    • 在快速恢复中,对于引起 TCP 进入快速恢复状态的缺失报文段,对收到的每个冗余的 ACK, cwnd 的值增加 一个 MSS。 最终,当对丢失报文段的一个 ACK 到达时,TCP 在降低 cwnd 后进入拥塞避免状态。如果出现超时事件,快速恢复在执行如同在慢启动和拥塞避免中相同的动作后,迁移到慢启动状态:当丢包事件出现时,cwnd 的值被设置为 1 个 MSS,并且 ssthresh 的值设置为 cwnd 值的 一半 。
  • TCP 拥塞控制:回顾
    • 忽略一条连接开始时初始的慢启动阶段,假定丢包由 3 个冗余的 ACK 而不是超时指示,TCP 的拥塞控制是:每个 RTT 内 cwnd 线性(加性)增加 1MSS, 然后出现 3 个冗余 ACK 事件时 cwnd 减半(乘性减)。 因此,TCP 拥塞控制常常被称为加性增、乘性减(Additive-Increase. Multiplicative-Decrease , AIMO) 拥塞控制方式 。
  • 对 TCP 吞吐量的宏观描述
    • 在一个特定的往返间隔内,TCP 发送数据的速率是拥塞窗口与当前 RTT 的函数与窗口长度是 w 字节,且当前往返时间是 RTT 秒时 ,则 TCP 的发送速率大约是 w/RTI。 于是, TCP 通过每经过 1 个 RTT 将 w 增加 1 个 MSS 探测出额外的带宽,直到一个丢包事件发生为止。 当一个丢包事件发生时,用 W 表示 w 的值。假设在连接持续期间 RTT 和 W 几乎不变 ,那么 TCP 的传输 速率在 W/( 2 x RTT ) 到 W/RTT 之间变化 。所以一条平均的吞吐量为(3/4 x W)/RTT。
  • 高宽带路径的 TCP
    • 考虑一条具有 1500 字节报文段和 1OOms RTT 的 TCP 连接,假定我们要通过这条连接以 1OGbps 速率发送数据。根据 [RFC 3649], 我们注意到使用上述 TCP 吞吐量公式 ,为了取得 1OGbps 吞吐量,平均拥塞窗口长度将需要是 83333 个报文段。对如此大量的报文段,使我们相当关注这 83333 个传输中的报文段也许会丢失。为了取得 1OGbps 的吞吐量,今天的 TCP 拥塞控制算法仅能容忍 \(2\times10^{-10}\)的报文段丢失概率,这是一个非常低的值。这种观察导致许多研究人员为这种高速环境特别设计新版 TCP
  • 公平性
    • TCP 趋于在竞争的多条 TCP 连接之间提供对一段瓶颈链路带宽的平等分享
    • 在理想化情形中,我们假设仅有 TCP 连接穿过瓶颈链路,所有的连接具有相同的 RTT 值,且对于一个主机-目的地对而言只有一 条 TCP 连接与之相关联。实践中,这些条件通常是得不到满足的,客户-服务器应用因此能获得非常不平等的链路带宽份额。特别是,已经表明当多条连接共享一个共同的瓶颈链路时,那些具有较小 RTT 的连接能够在链路空闲时更快地抢到可用带宽,因而将比那些具有较大 RTT 的连接享用更高的吞吐量
    • 公平性和 UDP: 从 TCP 的观点来看,运行在 UDP 上的多媒体应用是不公平的,因为它们不与其他连接合作,也不适时地调整其传输速 率。因为 TCP 拥塞控制在面临拥塞增加时,将降低其传输速率,而 UDP 源则不必这样做,UDP 源有可能压制 TCP 流量 。
    • 公平性和并行 TCP 连接: 当一个应用使用多条并行连接时,它占用了一条拥塞链路中较大比例的带宽。
  • 明确拥塞通告:网络辅助拥塞控制
    • 在网络层,IP 数据报首部的服务类型字段中的两个比特被用于 ECN。 路由器所使用的一种 ECN 比特设置指示该路由器正在历经拥塞。该拥塞指示则由被标记的 IP 数据报所携带,送给目的主机,再由目的主机通知发送主机