"> "> 计算机网络-传输层 | Yufei Luo's Blog

计算机网络-传输层

传输层服务

进程到进程通信

传输层位于应用层和网络层之间,它在两个应用层之间提供进程到进程的通信,两个进程分别位于本地和远程主机上。

注意:网络层负责的是计算机层次的通信(即主机到主机),但是网络层协议只是把报文传递到目的计算机。由于报文需要递交给正确的进程,而这一部分正是传输层负责的部分。

寻址:端口号

一个远程计算机在同一时间可以运行多个服务器程序。因此在通信过程中,我们需要定义本地主机、本地进程、远程主机和远程进程。本地主机和远程主机使用IP地址来定义,而本地进程和远程进程则是通过端口号来定义的。在TCP/IP协议簇中,端口号是0~65536之间的16位整数。

客户程序一般使用临时端口号来定义它自己,临时表明这个端口号是短期的。为了客户-服务器程序可以正常工作,临时端口号推荐值为大于1023。

对于服务器而言,TCP/IP协议使用全局端口号,它们被称为熟知端口号。但是这一条规则也有例外,例如一些客户端也可能被分配熟知端口号。

ICANN将端口号编码划分为如下的三个范围:

  • 熟知端口:端口号范围0~1023,由ICANN分配和控制
  • 注册端口:端口号范围1024~49151,ICANN不分配也不控制,它们可在ICANN注册以防止重复
  • 动态端口:端口号范围49152~65535,这一范围内的端口号即不受控制也不需要注册,可以由任何进程使用。它们是临时或者私有端口号。

一个IP地址和一个端口号结合起来被称为套接字地址,客户套接字地址唯一定义了客户进程,而服务器套接字地址唯一定义了服务器进程。

封装与解封装

为了将报文从一个进程发送到另一个进程,传输层协议负责封装和解封装报文。封装在发送端发生,当进程有报文要发送,它将报文与一组套接字地址和其他信息一起发送到传输层,这依赖于传输层协议。传输层接收这些数据并加入到传输层头部。

解封装发生在接收端。当报文到达目的传输层,头部被丢弃,传输层将报文传递到应用层运行的进程。如果需要响应接收到的报文,发送方的套接字地址被发送到进程。

多路复用与多路分解

多路复用指的是一个实体从一个以上的源接收到数据项,源端的传输层执行复用。例如一个用户将不同进程的请求发送到对应的服务器进程。

多路分解指的是一个实体将数据项传递到一个以上的源,目的端的传输层执行多路分解。例如一个服务器接收到应该分发给不同进程的请求。

流量控制

每当一个实体创建数据项并且有另一个实体消耗它们时,就存在生产速率和消费速率的平衡问题。流量控制主要是解决数据项的生产比消费快的问题。

推或拉

发送方生产数据项时,它无需事先获得消费者请求就发送,这种传递被称为推;如果生产者在消费者请求这些数据时才进行传送,这种传递被称为拉。

当生产者数据项时,消费者需要相反方向的流量控制,以此来防止丢弃这些数据项。因此消费者需要告诉生产者停止传递,并且当它再次准备好接受数据时通知生产者。当消费者拉数据项时则不需要流量控制。

传输层流量控制

传输层通信中,四个实体的关系如下:

  • 发送方的应用层是一个生产者,它生产报文块并推给传输层
  • 发送方传输层既是生产者又是消费者,它消费来自于应用层的报文块,同时有奖报文封装并传给接收方传输层
  • 接收方传输层既是生产者又是消费者,它消费从发送方接收来的分组,同时解封装报文并传给应用层
  • 接收方的应用层通常使用拉传递,传输层等待应用层进程请求报文,它是一个消费者

因此,这一过程至少需要两种流量控制:从发送方传输层到发送方应用层的流量控制,以及接收方传输层到发送方传输层的流量控制。

缓冲区

流量控制通常使用缓冲区来实现,一个位于发送方传输层,另一个位于接收方传输层(也就是说缓冲区位于消费者处)。消费者向生产者发送信号从而进行流量控制通信,当缓冲区满的时候,通知生产者停止传输;当有空闲位置的时候,通知生产者可以再次传输。

差错控制

在因特网中,网络层是不可靠的,应用层的可靠性是通过传输层来实现的。传输层的差错控制通过负责以下几个方面来实现可靠性:

  • 发现并丢弃被破坏的分组
  • 记录丢失和丢弃的分组并重传
  • 识别重复分组并丢弃
  • 缓冲失序分组直到丢失的分组到达

大多数情况下,接收方传输层管理差错控制,它通过告知发送方传输层存在问题来进行管理。

序号

可以在传输层分组中加入一个字段来保存分组的序号。当分组被破坏或者丢失,接收方传输层可以按照某种方式通知发送方传输层利用序号来重传分组;如果两个接收到的分组具有相同序号,接收方传输层可以发现重复分组;可以通过观察序号间隔来辨别失序分组。

分组一般按序编号,假设分组头部允许序号最多为\(m\)比特位,那么所有的序号都是模\(2^m\)的。

确认

接收方可以为每一组正确到达的分组发送一个确认(ACK)。当一个分组被发送,发送方就开启一个计时器,如果ACK在计时器超时之前没有到达,那么发送方就重新发送这个分组。重复的分组可以被接收方默默丢弃;失序的分组既可以被丢弃,也可以存储直到丢失的那个分组被传输过来。

流量和差错控制的组合

由于流量控制要求使用两个缓冲区,一个在发送端另一个在接收端;而差错控制也要求两端使用序号和确认号。因此如果我们使用两个带有序号的缓冲区,一个位于发送端,一个位于接收端,便可将流量控制与差错控制功能结合起来。

在发送端,当分组准备发送时,我们使用下一个缓冲区空闲位置号码\(x\)作为分组的序号;当分组被发送,一个分组的备份存储在位置\(x\),直到与被发送分组相关的确认信息到达时,将这一位置清除出来。

在接收端,当带有序号\(y\)的分组到达时,它也被存储在缓冲区的位置\(y\)上,直到应用层准备好接收它。此时发送一个确认表明分组\(y\)到达。

拥塞控制

如果网络中的复杂大于网络的容量,那么网络就可能会发生拥塞。TCP协议提供了拥塞控制机制,它控制拥塞并将负载保持在容量以内。

无连接和面向连接服务

无连接服务

在无连接服务中,源进程需要将报文分成传输层可接受大小的数据块,并把它们一个个地传递到传输层。传输层将每一个数据块看作彼此没有关系的单元,因此,它们可能会失序地传递给服务器进程。

流量控制、差错控制以及拥塞控制都不能在无连接服务中有效实现。

面向连接服务

在面向连接的服务中,首先需要建立客户和服务器之间的逻辑连接。只有连接建立之后才能进行数据交换。在数据交换之后,连接需要拆除。

在面向连接协议中,可以实现流量控制、差错控制以及拥塞控制。

UDP协议

概述

用户数据报协议(User Datagram Protocol, UDP)是无连接不可靠传输层协议。它不提供主机到主机通信,它除了提供进程到进程之间的通信之外没有给IP服务增加任何内容。此外它进行非常有限的差错检验。

UDP是一个简单的协议,开销很小。如果一个进程想发送一个很短的报文,而且不在意可靠性,就可以使用UDP。使用UDP发送一个很短的报文,在发送方和接收方之间的交互要比使用TCP时少得多。

用户数据报

UDP分组被称为用户数据报,有8个字节的固定头部,这个头部由4个字段组成,每个字段2字节。头两个字段定义了源和目的端口号,第三个字段定义了用户数据报的总长,即头部加数据的长度。16位可以定义的总长度范围是0~65535,但是因为UDP数据报需要存储在总长度为65535的IP数据报中,因此总长度需要更小一些。最后一个字段可以携带可选校验和。一个UDP用户数据报的结构如下图所示:

UDP数据报

UDP服务

进程到进程的通信

UDP使用套接字地址提供进程到进程的通信,这是IP地址与端口号的组合。

无连接服务

UDP提供无连接服务,这表示UDP发送出去的每一个用户数据报都是一个独立的数据报。即使这些数据报来自于相同的源进程并且发送到相同的目的进程,不同的数据报之间也没有关系。用户数据报不进行编号,此外也没有像TCP协议那样的连接建立和终止。

无连接的一个结果就是使用UDP的进程不能向UDP发送数据流,并期望它将这个数据流分割成许多相关联的用户数据报。相反,每一个请求需要足够小以使其可以被装入用户数据报中,因此只有那些发送短报文的进程才应当使用UDP。

UDP没有流量控制,因而也没有窗口机制。如果到来的报文太多时,接收方可能会溢出。因此,如果需要流量控制,这个服务应该由使用UDP的进程来提供。同时,UDP也不提供拥塞控制。UDP假设被发送的分组很小且零星,不会造成拥塞。但是UDP被用作音频和视频的交互实时传输时,这一假设可能不成立。

校验和

UDP没有差错控制机制,发送方不知道报文是丢失还是重传,仅仅提供了简单的校验和功能。因此如果需要差错控制需要由应用层提供。

UDP的校验和是可选的,如果不计算校验和,则将校验和字段全部填充为0。如果计算校验和时恰巧校验和全部为0,则将它改为全1。这一方法不会产生混淆,因为校验和的值在正常情况下不会全为1。

封装和解封装

UDP协议提供了报文的封装和解封装功能。

多路复用与多路分解

在运行TCP/IP协议簇的主机上只有一个UDP,但可能有多个想使用UDP服务的进程。UDP使用多路复用和多路分解来处理这种情况。

UDP应用

UDP特性

UDP连接具有的特性以及它们的优势和劣势如下:

  • 无连接服务:当客户需要向服务器发送短请求并接收短响应时,这一特性是优势,因为这种情况下建立和关闭连接的开销可能很可观。假设请求和响应各自可以填充进一个数据报时,TCP连接需要至少交换9个分组,而UDP最少只需要2个。同时,无连接服务提供了更小的延迟,如果延迟是应用的重要问题时选择UDP连接更可取。
  • 缺乏差错控制:TCP提供可靠服务,如果报文一部分丢失或被破坏则需要重传。这就意味着接收方传向应用层的不同报文间有不一致的延迟。对于一些应用来说,这一延迟可能至关重要。
  • 缺乏拥塞控制:在一些网络中可能出错的概率较大,如果使用TCP连接需要多次重发,这样便会促使拥塞的发生或者使得拥塞情况加重。因此,一些情况下,这一特性可以看作是优势。

典型应用

  • 需要简单的请求-响应通信,而较少考虑流量控制和差错控制,例如DNS协议。如果需要传输成块数据的进程如FTP,则通常不适用UDP协议。
  • 适用于应用层实现了内部流量控制和差错控制机制的进程,如TFTP协议。
  • 对于多播来说UDP是一个合适的传输协议。
  • UDP可用于管理进程,如SNMP协议。
  • UDP可用于某些路由选择更新协议,如路由选择信息协议(RIP)。
  • UDP通常用于交互实时应用,如Skype,这些应用无法忍受报文之间的不一致延迟。

TCP协议

概述

传输控制协议(Transmission Control Protocol, TCP)是一个面向连接可靠的协议。TCP显式定义了连接建立、数据传输以及连接拆除阶段来提供面向连接服务。

TCP服务

### 进程到进程的通信

与UDP一样,TCP通过使用端口号来提供进程到进程的通信

流传递服务

TCP是一个面向流的协议,它允许发送进程以字节流的形式传递数据,并且接收进程也以字节流的形式接收数据。TCP建立一种环境,在这种环境中,两个进程之间类似于有一条假想的“管道”连接,发送进程产生字节流并输入到管道,接收进程从管道中读出这些字节流。

因为发送和接收进程可能以不同的速度写入和读出数据,所以TCP需要用于存储的缓冲区。缓冲区一般使用循环数组来实现。

由于IP层作为TCP服务的提供者,它需要以分组的方式而不是字节流的方式发送数据。因此,在传输层,TCP将多个字节组合在一起成为一个分组,这个分组被称为段,同时给每个段添加头部,并将该段传递给IP层。

上述这一系列流程可以用下图来表示:

TCP缓冲区

全双工通信

TCP提供全双工服务,即数据可以在同一时间双向流动。每一个方向TCP都有发送和接收缓冲区,它们可以在双向发送和接收段。

多路复用和多路分解

TCP在发送端执行多路复用,在接收端执行多路分解。由于TCP是一个面向连接的协议,因此需要为每对进程建立连接。

面向连接的服务

TCP是一种面向连接的协议。位于站点A的一个进程和与站点B的另外一个进程想要进行数据的发送和接收时要经过如下三步:

  1. 在两个TCP之间建立一个连接
  2. 在两个方向交换数据
  3. 连接终止

上述建立的连接是一个逻辑连接,而不是一个物理连接。TCP建立一种面向字节流的环境,在这种环境中,TCP能承担按顺序传递这些字节到其他站点的服务。

可靠的服务

TCP是一种可靠的传输协议,它使用确认机制来检查数据是否安全和完整地到达。

TCP的特点

序号系统

字节序号

TCP为在一个连接中传输的所有数据字节编号,在每个方向上的序号都是独立的。当TCP接收来自一个进程的数据字节时,TCP将它们存储在发送缓冲区中并给它们编号。在编码时,不必从0开始编码,TCP在0到\(2^{32}-1\)之间生成一个随机数作为第一个字节的序号。这些字节序号被用于流量和差错控制。

序号

字节被编号之后,TCP对发送的每一个段也分配一个序号。第一个段的序号是初始随机生成的那个字节序号;其他段的序号是之前段的序号加上之前段携带的字节数。

确认号

TCP中的通信是全双工的,当建立一个连接时,双方同时都能发送和接收数据。因此,每一方会使用确认号来确认它已经收到的字节。确认号的值是该方向预期接收的下一个字节的序号,如果接收方安全并完整地接收到这一字节的序号,就会将它加1。

TCP分组—段

格式

在TCP中的分组被称为段,它包含20~60字节的头部,接着是来自应用程序的数据。如果没有选项,那么头部为20字节;如果有选项则最多是60字节。TCP的段格式如下图所示:

TCP段结构

一些头部字段的意义如下:

  • 源端口地址:一个16位字段,定义了在主机中发送该段的应用程序的端口号。
  • 目的端口地址:一个16位字段,定义了主机中接收该段的应用程序的端口号。
  • 序号:这个32位字段定义了一个数,分配给段中数据的第一个字节。这个序号告诉目的端,在这个序列中的哪一个字节是该段的第一个字节。在连接建立时,每一方都使用随机数产生器生成一个初始序号(Initial Sequence Number, ISN),通常每一个方向的ISN都不同。
  • 确认号:这个32位字段定义了段的接收方期待从对方接收的字节号。如果段的接收方成功地接收了对方发来的字节号x,确认号就被定义为x+1,确认和数据可以捎带一起发送。
  • 头部长度:这个4位字段指明了TCP头部中有多少个4字节长的字。由于头部长度可以在20~60字节之间,因此这个字段的值在5~15之间。
  • 控制:这个字段定义了6种不同的控制位或标记,在同一时间可以设置一位或多位。其中:
    • URG:紧急指针有效
    • ACK:确认有效
    • PSH:请求推送
    • RST:连接复位
    • SYN:同步序号
    • FIN:终止连接
  • 窗口大小:定义对方必须维持的窗口的大小(以字节为单位)。这个字段长度为16位,因此窗口的最大长度为65535字节。这个值通常称为接收窗口,它由接收方确定。
  • 校验和:TCP的校验和是强制的,它的计算与UDP相同。
  • 紧急指示符:这个16位字段只有当紧急标志置位时才有效,这个段包含了紧急数据。它定义了一个数,将此数加到序号上就可以得出此段数据部分中最后一个紧急字节。
  • 选项:在TCP头部可以有最多40字节的可选信息。

封装

一个TCP段封装了来自应用层的数据。TCP段被封装在IP数据报中,IP数据报被封装在数据链路层的帧中。

TCP连接

连接建立

在TCP中连接的建立被称为三次握手。我们假设客户应用程序想要与另一个服务器应用程序之间使用TCP作为传输层协议建立连接。

这一过程从服务器开始,服务器程序会一直处于被动打开状态,准备接收从任何一个用户发过来的连接。当客户程序想要与某个特定服务器进行TCP连接时,它发出请求进行主动打开。接下来,TCP进行三次握手的过程来建立连接,这一过程如下:

  1. 用户发送的第一个段是SYN段。这个段只有SYN标志被置位,它被用于序号同步。当数据传输开始时,用户随机选择一个数字作为初始序号ISN。SYN段不包含确认号,也没有定义窗口大小。需要注意的是,SYN段是一个控制段并且不携带数据,但是它需要消耗一个序号(因为它需要被确认),因此可以说SYN段携带了一个假想字节。
  2. 服务器发送第二个段,即两个标志位SYN和ACK置位的段。这个段有两个目的:首先,它是另一方向通信的SYN段,服务器使用这个段来初始化序号,这个序号用于给从服务器发向客户的字节编号;同时,服务器也通过给ACK置位并展示下一个序号来确认接收到来自客户的SYN段。因为它包含确认,因此也需要定义接收窗口(即rwnd)给客户使用。同时,因为这个段也起到SYN段的作用,它需要被确认,因此它也占用一个序号。
  3. 客户发送第三个段。这个段仅仅是一个ACK段。它使用ACK标志和确认序号字段来确认收到了第二个段。如果不携带数据,ACK段没有占用任何序号;也有一些实现允许第三个段在连接阶段从客户端携带第一块数据,这种情况下段消耗的序号与数据字节数相同。

上述的过程可以用下图来表示:

TCP三次握手

在TCP中,连接建立的过程容易遭受到SYN泛洪攻击的严重安全问题。一个恶意攻击者将大量的SYN段发送到一个服务器,在数据报中通过伪装源IP地址假装这些SYN段来自于不同的客户端。此时,服务器发送SYN+ACK段给这些假客户,但是这些段都会丢失。服务器会等待第三段的握手过程,此时许多资源被占用但是没有被使用。如果在短时间内,SYN段的数量很大,服务器最终会因为耗尽资源而崩溃。一些TCP的实现拥有减轻SYN攻击影响的策略。

数据传输

连接建立之后,便可进行双向的数据传输,客户端与服务器双方都可以发生数据和确认。

当两个应用程序进行交互式通信时,希望收到立即响应。此时,发送端的TCP需要设置推送位(PSH)来告诉接收端的TCP,这个段所包含的数据需要尽快传递给接收应用程序,而不需要等待更多数据的到来。此时,发送端的TCP也不会等待窗口被填满,它创建一个段就立即将其发送。

如果一些情况下,应用程序需要发送紧急字节,需要另一端的应用以特殊方式对待。此时,应用程序会将URG标志置位。同时,紧急数据被放在段的开始,并使用紧急指针字段定义紧急数据的结束。而在其余部分,则可以存放来自于缓冲区的普通数据,这一部分数据是非紧急的。但是TCP的紧急数据并不意味着优先服务,仅仅是让接收端TCP通知应用程序紧急数据的开始和结束,留给应用程序决定如何处理紧急数据。

连接终止

交换数据双方的任意一方都可以关闭连接。连接终止的实现有两种方法:三次挥手和带有半关闭选项的四次挥手。

三次挥手

三次挥手断开连接的步骤如下:

  1. 客户TCP发送一个FIN段,其中的FIN标志被置位。同时,FIN段可以包含客户要发送的最后数据块。如果它只是控制段,则只占有一个序号。
  2. 服务器TCP接收到FIN段之后,通知进程并发送第二个FIN+ACK段,证明它接收到了来自客户端的FIN段,同时告诉客户端,服务器端的连接已关闭。这个段还可以包含来自服务器的最后数据块。如果不携带数据,则只占用一个序号。
  3. 客户端的TCP发送最后一个ACK段,证明它接收到了服务器的FIN段。这个段包含确认号,它是来自服务器的FIN段的序号再加1。这个段不携带数据也不占用序号。

这一过程可总结为下图:

TCP三次挥手

带有半关闭选项的四次挥手

在TCP中,一端可以在停止发送数据之后继续接收数据,这就是所谓的半关闭。虽然任意一端都可发出半关闭指令,但是通常情况下是由客户端发起。例如,当服务器在开始处理之前需要接收到所有的数据,此时就会出现半关闭。客户端发送全部数据之后,它在客户到服务器方向便可关闭连接;但是为了接收返回数据,服务器到客户的方向必须保持打开。此时的关闭过程为四次挥手,它的过程如下:

TCP四次挥手

连接重置

在一段的TCP可能会拒绝连接请求、终止已存在的连接、或是结束空闲连接。这些操作是通过RST标志完成的。

TCP的窗口

TCP在每个方向的数据传输上使用两个窗口:发送和接收窗口,也就是说双向通信有四个窗口。

发送窗口

发送窗口是一个想象的盒子,它覆盖了处于运送途中的以及可以被发送的数据分组序号。在每个窗口位置,一些序号定义了已经被发送的分组,其他序号定义了可以被发送的分组。

在任何时候,发送窗口将序号从左向右分成四部分:

  1. 窗口左侧:已经确认的分组的序号,发送方可以丢弃掉这些分组
  2. 未完成分组:发送方已经发送,但是状态未知的序号,发送方需要等待,从而确认这些分组是否已被接收还是丢失
  3. 可发送分组:可以发送的分组的序号,但是相应的数据还没有从应用层接收到
  4. 窗口右侧:直到窗口滑动之前都不能使用的序号

在TCP中使用的发送窗口中,窗口的大小是字节的数量,控制窗口的变量是以字节为单位的。在某些实现中,TCP可以存储来自于进程的数据并且在之后发送它们。同时,TCP只使用一个计时器。计时器被用来实现分组的重发,在发送一个分组时需要打开计时器(如果已运行则不用再打开),当计时器终止时,发送方需要重发所有的未完成分组。

TCP的发送窗口如下图所示:

TCP发送窗口

接收窗口

接收窗口用于确保正确的分组数据被接收,并且确保正确的确认被发送。

TCP允许接收进程以自己的速率拉取数据,因此接收方部分被分配缓冲区可以被已接收并且确认的字节所占据,但是它们正在等待被接收进程拉过去。因此,接收窗口的大小总是小于或等于缓冲区大小,它决定了接收窗口在被淹没之前可以从发送方接收的字节数量,又被称为rwnd。

同时,TCP协议中的主要确认机制是累积确认,它声明了下一个预期接收字节。在TCP的新版本中也使用了选择性确认。

TCP的接收窗口如下图所示:

TCP接收窗口

流量控制

为了实现流量控制,TCP可以迫使发送方和接收方调整它们的窗口大小。当更多的数据从发送方到来时,接收方窗口关闭;当更多的数据被进程拉取后,它打开窗口。发送窗口的打开、关闭和收缩由接收方控制。

差错控制

TCP使用差错控制来提供可靠性,它包括用于检测并重发损坏段的机制、用于重发丢失段的机制、用于存储失序的段直到丢失段到达的机制、以及检测并丢弃重复段的机制。上述机制主要是通过使用校验和、确认和超时来完成的。

校验和

TCP的每个段都包括校验和字段,用于检查损坏的段。如果段被损坏,它将目的端TCP丢弃,因此发送端会认为其丢失而重发。

确认

TCP使用确认方法来证实收到了数据段,不携带数据但是占用序号额一些控制段也需要确认,但是ACK段因为不占用序号所以不需要确认。

TCP的确认方式有两种,累积确认和选择性确认。累积确认指的是接收方通告下一个预期接收的字节,忽略所有的失序段。TCP头部的32位ACK字段用于累积确认,且只有当ACK标志为1时才有效。选择性确认(SACK)指的是向发送方报告额外信息,包括失序字节块和重复字节块。SACK以TCP头部末端选项的形式实现。

接收方产生确认的规则有:

  • 终端A向终端B发送一个数据段时,必须包含一个确认,这个确认给出下一个期待接收的序号。这个规则降低了所需段的数量。
  • 如果只有一个未完成的有序段,接收方需要延迟发送ACK段。这一规则减少了ACK段。
  • 任何时候不能多于两个有序的未确认段存在。这样防止了不必要的重传,避免引起网络拥塞。
  • 当一个失序段到达,且序号大于预期,接收方立即发送一个ACK段,声明下一个预期段的序号。这使得丢失段可以快速重传。
  • 当一个丢失段到达,接收方发送一个ACK段,声明下一个预期序号。这通知接收方被报告丢失段已经到达。
  • 如果重复段到达,接收方丢弃段,但是立即发送一个确认指出下一个预期的有序段。这解决了当ACK段丢失时的一些问题。

重传

当一个段被发送,它会被储存在一个队列中直到被确认。当重传计时器超时或者当发送方接收到对队列中第一个段的三次重复ACK时,就重传这个段。

发送方TCP为每个连接维护一个重传超时,当计时器到时即超时,TCP重发队列中具有最小序号的段并重启计时器。

而三次重复ACK立即重发的规则,允许发送方不等待超时而重传,这加速了因特网中的服务。这一特性也被称为快速重传。

失序段

TCP不丢弃失序段,它们暂时存储这些失序段,并将其标记为失序段直到缺失的段到达。但是TCP会确保传递给进程的段是非失序的。

拥塞控制

拥塞窗口

TCP使用称为拥塞窗口(cwnd)的变量来控制段的发送数量,这个变量的值由网络中的拥塞情况所控制。cwnd变量和rwnd变量一起定义了TCP中的发送窗口大小。cwnd与网络中间的拥塞相关,而rwnd与终端的拥塞相关,实际窗口的大小为二者中的最小值。

拥塞检测

TCP的发送方使用两个事件来作为网络中拥塞的标志:

  • 超时:如果一个TCP发送方在超时之前没有接收到对于某个段或者某些段的ACK,那么它就假设它们丢失,并且丢失是由于严重拥塞引起的。
  • 接收到三次重复ACK:当接收方发送三次重复ACK时,这意味着一个段丢失,说明网络此时处于轻微拥塞或者已经从拥塞中恢复。

拥塞策略

慢启动

慢启动算法是基于拥塞窗口大小的思想,它以最大段长度(MSS)开始,但是每当一个确认到达时它只增加一个MSS。

初始时cwnd=1,当一个ACK到达时,cwnd=cwnd+1。这一算法启动慢,但是它是以指数增长的。因此,它不能一直继续下去,存在一个停止该阶段的阈值,当窗口中的字节达到这个阈值时,慢启动停止且下一个阶段开始。

拥塞避免

由于慢启动算法使得拥塞窗口大小按照指数规律增大,因此为了在拥塞发生之前避免堵塞,TCP定义了另一个被称为拥塞避免的算法。

在这个算法中,每次整个窗口的所有段都被确认之后,拥塞窗口才增加1。也就是说,此时如果有一个ACK到达,cwnd=cwnd+(1/cwnd)。此时,增长速率以每次往返时间为单位是线性的,因此这种方法比慢启动方法保守得多。

快速恢复

快速恢复算法在TCP中是可选的。它开始于三次重复ACK到达,这被解释为网络的轻微阻塞。这个算法也是加性增加的,在三次重复ACK触发使用这个算法之后(三次重复ACK通常会使得cwnd的值减小),当一个重复ACK到达时,cwnd=cwnd+(1/cwnd)。

TCP计时器

重传计时器

为了重传丢失的段,TCP在整个连接期间使用一种重传计时器来处理重传超时(RTO)。重传计时器的使用有如下规则:

  • 当TCP发送位于发送队列前端中的段时,它开启计时器
  • 当计时器到时,TCP重发队列前端的第一个段并且重启计时器
  • 当一个或者多个段被累积确认,一个或者多个段从队列中被清除,如果清除至队列为空,则停止计时器。而当队列不为空时重启计时器。

RTO的计算依赖于RTT的计算,我们将每一个包从发出到接收的时间称为往返时间(Round-Trip Time, RTT)。RTO的计算公式为:\(RTO=RTT_{S}+4\times RTT_{D}\),其中\(RTT_S\)代表平滑RTT,\(RTT_D\)代表RTT偏差。将每一次测量的RTT记作\(RTT_M\),二者的值通过多次测量\(RTT_M\)并迭代计算而得。在第一次测量后,\(RTT_{S}=RTT_{M}\)\(RTT_{D}=RTT_{M}/2\);而在这之后每一次测量出新的\(RTT_M\)\(RTT_S\)\(RTT_D\)通过下面两个式子更新:\(RTT_{S}=(1-\alpha)RTT_{S}+\alpha \times RTT_{M}\)\(RTT_{D}=(1-\beta)RTT_{D}+\beta \times |RTT_{S}-RTT_{M}|\)

坚持计时器

为了处理0窗口大小的通告,TCP需要使用坚持计时器。如果接收TCP声明了0窗口大小,那么发送TCP停止传输段,直到接收TCP发送一个ACK段声明非零的窗口大小。由于这个声明非0的ACK段可能会丢失,而且它不存在重传计时器,如果不使用坚持计数器就可能会因为双方TCP互相等待造成死锁。

因此,当发送方TCP接收一个窗口大小为0的确认时,开启坚持计时器。当坚持计时器到时,发送方TCP发送一个特殊的探测段,这个段只包含一个字节的新数据,同时有一个序号,但是序号从来不被确认。探测报文引发接收方TCP重发确认。

保活计时器

保活计时器用于防止两个TCP之间的长期空闲连接。假设一个用户与服务器建立了连接,传输了一些数据并进入沉默状态,但是此时连接会永远保持打开。为了消除这种情况,每当服务器从客户收到一次数据就重置保活计时器。而当保活计时器超时之后,它发送一个探测段,如果多次发送探测段之后仍然无响应,那么服务器就认为用户出现故障,会终止连接。

时间等待计时器

时间等待(2MSL)计时器在连接终止期间使用。最大报文段寿命(Maximum Segment Lifetime, MSL)是任意报文在被丢弃之前在网络中的存在时间。当TCP执行主动关闭并发送最后一个ACK时,使用2MSL计时器,连接保持2MSL的时间,从而允许TCP重发最后一个ACK,以防ACK丢失。

参考

  1. 计算机网络:自顶向下方法