计算机网络基础 之五:运输层

前言

运输层,解决的是计算机程序到计算机程序之间的通信问题,即所谓的“端”到“端”的通信。引入运输层的原因: 增加复用和分用的功能、 消除网络层的不可靠性、 提供从源端主机到目的端主机的可靠的、与实际使用的网络无关的信息传输。运输层是ISO/OSI的第四层,处于通信子网和资源子网之间,是整个协议层次中最核心的一层

所以,本文会比较全面而有节制的介绍有关运输层的相关知识,尽量使读者能够把握其脉络,而不至于费太多精力。

概述

运输层是整个网络体系结构中的关键层次之一。一定要弄清以下一些重要概念:

  1. 运输层为相互通信的应用进程提供逻辑通信。
  2. 端口和套接字的意义。
  3. 无连接的UDP的特点。
  4. 面向连接的TCP的特点。
  5. 在不可靠的网络上实现可靠传输的工作原理,停止等待协议和ARQ协议。
  6. TCP的滑动窗口、流量控制、拥塞控制和连接管理。

从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。当网络的边缘部分中的两台主机使用网络的核心部分的功能进行端到端的通信时,只有主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到下三层的功能。

进程之间的通信

为什么需要运输层?

这是因为,真正进行通信的实体是在主机中的进程,是这台主机中的一个进程和另一台主机中的一个进程在交换数据(即通信)。因此严格地讲,两台主机进行通信就是两台主机中的应用进程互相通信。IP协议虽然能把分组送到目的主机,但是这个分组还停留在主机的网络层而没有交付主机中的应用进程。从运输层的角度看,通信的真正端点并不是主机而是主机中的进程。也就是说,端到端的通信是应用进程之间的通信。

在一台主机中经常有多个应用进程同时分别和另一台主机中的多个应用进程通信。这个很容易明白,因为你现在所使用的设备肯定能多开有联网功能的程序。这表明运输层有一个很重要的功能—复用(multiplexing)分用(demultiplexing)。这里的“复用”是指在发送方不同的应用进程都可以使用同一个运输层协议传送数据(当然需要加上适当的首部),而“分用”是指接收方的运输层在剥去报文的首部后能够把这些数据正确交付目的应用进程。

下图为运输层作用图。

运输层作用示意图

图中两个运输层之间有一个双向粗箭头,写明“运输层提供应用进程间的逻辑通信”。“逻辑通信”的意思是:从应用层来看,只要把应用层报文交给下面的运输层,运输层就可以把这报文传送到对方的运输层(哪怕双方相距很远,例如几千公里),好像这种通信就是沿水平方向直接传送数据。但事实上这两个运输层之间并没有一条水平方向的物理连接。数据的传送是沿着图中的虚线方向(经过多个层次)传送的。“逻辑通信”的意思是“好像是这样通信,但事实上并非真的这样通信”。

这和之前提到的透明十分类似。

根据应用程序的不同需求,运输层需要有两种不同的运输协议,即面向连接的TCP无连接的UDP,这两种协议就是本文要讨论的主要内容。当运输层采用面向连接的TCP协议时,尽管下面的网络是不可靠的(只提供尽最大努力服务),但这种逻辑通信信道就相当于一条全双工的可靠信道。但当运输层采用无连接的UDP协议时,这种逻辑通信信道仍然是一条不可靠信道。

运输层的两个主要协议

TCP/IP运输层的两个主要协议都是互联网的正式标准,即:

  1. 用户数据报协议UDP(User Datagram Protocol) [RFC 768]
  2. 传输控制协议TCP (Transmission Control Protocol) [RFC 793]

UDP在传送数据之前不需要先建立连接。远地主机的运输层在收到UDP报文后,不需要给出任何确认。虽然UDP不提供可靠交付,但在某些情况下UDP却是一种最有效的工作方式。例如通讯类软件,容忍出现一定杂音,但要求实时性。

TCP则提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。TCP不提供广播或多播服务。由于TCP要提供可靠的、面向连接的运输服务,因此不可避免地增加了许多的开销,如确认、流量控制、计时器以及连接管理等。这不仅使协议数据单元的首部增大很多,还要占用许多的处理机资源。例如电子邮件,确保文本不出错,可能缓慢,但更安全可靠。

运输层的端口

应用层所有的应用进程都可以通过运输层再传送到IP层(网络层),这就是复用。运输层从IP层收到发送给各应用进程的数据后,必须分别交付指明的各应用进程,这就是分用。显然,给应用层的每个应用进程赋予一个非常明确的标志是至关重要的。

解决这个问题的方法就是在运输层使用协议端口号(Protocol port number),或通常简称为端口(Port)。这就是说,虽然通信的终点是应用进程,但只要把所传送的报文交到目的主机的某个合适的目的端口,剩下的工作(即最后交付目的进程)就由TCP或UDP来完成。

请注意,这种在协议栈层间的抽象的协议端口是软件端口,和路由器或交换机上的硬件端口是完全不同的概念。硬件端口是不同硬件设备进行交互的接口,而软件端口是应用层的各种协议进程与运输实体进行层间交互的一种地址。不同的系统具体实现端口的方法可以是不同的(取决于系统使用的操作系统)。

TCP/IP的运输层用一个16位端口号来标志一个端口。但请注意,端口号只具有本地意义,它只是为了标志本计算机应用层中的各个进程在和运输层交互时的层间接口。在互联网不同计算机中,相同的端口号是没有关联的。16位的端口号可允许有65535个不同的端口号,这个数目对一个计算机来说是足够用的。

下面将分别讨论UDP和TCPO,UDP比较简单,主要讨论TCP。

用户数据报协议 UDP

概述

用户数据报协议UDP只在IP的数据报服务之上增加了很少一点的功能,这就是复用和分用的功能以及差错检测的功能。UDP的主要特点是:

  1. UDP是无连接的,即发送数据之前不需要建立连接(当然,发送数据结束时也没有连接可释放),因此减少了开销和发送数据之前的时延。
  2. UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表(这里面有许多参数)。
  3. UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。这就是说,应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文。
  4. UDP没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的。它允许在网络发生拥塞时丢失一些数据,但却不允许数据有太大的时延。UDP正好适合这种要求。
  5. UDP支持一对一、一对多、多对一和多对多的交互通信。
  6. UDP的首部开销小,只有8个字节,比TCP的20个字节的首部要短。

首部格式

用户数据报UDP有两个字段:数据字段和首部字段。首部字段很简单,只有8个字节(如上图),由四个字段组成,每个字段的长度都是两个字节。各字段意义如下:

  1. 源端口源端口号.在需要对方回信时选用。不需要时可用全。
  2. 目的端口目的端口号。这在终点交付报文时必须使用。
  3. 长度UDP用户数据报的长度,其最小值是8(仅有首部))。
  4. 检验和检测UDP用户数据报在传输中是否有错,有错就丢弃。

当运输层从IP层收到UDP数据报时,就根据首部中的目的端口,把UDP数据报通过相应的端口,上交最后的终点——应用进程。

传输控制协议 TCP 概述

由于TCP协议比较复杂,因此本节先对TCP协议进行一般的介绍,然后再逐步深入讨论TCP的可靠传输、流量控制和拥塞控制等问题。

主要特点

TCP是TCP/IP体系中非常复杂的一个协议。下面介绍TCP最主要的特点。

  1. TCP是面向连接的运输层协议。这就是说,应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放己经建立的TCP连接。
  2. 每一条TCP连接只能有两个端点(endpoint),每一条TCP连接只能是点对点的(一对一)。这个问题后面还要进一步讨论。
  3. TCP提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。
  4. TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序在把数据传送给TCP的缓存后,就可以做自己的事,而TCP在合适的时候把数据发送出去。在接收时,TCP把收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据。
  5. 面向字节流。TCP 中的**“流”(stream)指的是流入到进程或从进程流出的字节序列**。TCP把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据。

连接

TCP把连接作为最基本的抽象。TCP的许多特性都与TCP是面向连接的这个基本特性有关。因此我们对TCP连接需要有更清楚的了解。

前面已经讲过,每一条TCP连接有两个端点。那么,TCP连接的端点是什么呢?不是主机,不是主机的IP地址,不是应用进程,也不是运输层的协议端口。TCP连接的端点叫做套接字(socket)插口。根据RFC 793的定义:端口号拼接到(concatenated with) IP地址即构成了套接字。因此,套接字的表示方法是在点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。例如,若IP地址是192.3.4.5而端口号是80,那么得到的套接字就是192.3.4.5:80

**每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定。**即:

TCP连接定义为:`{socket1, socket2}={(IP1: port1), (IP2: port2)}`

这里IP1和IP2分别是两个端点主机的IP地址,而port1和port2分别是两个端点主机中的端口号。TCP连接的两个套接字就是socket1和socket2。可见套接字socket是个很抽象的概念。

一定要记住:TCP连接的端点是个很抽象的套接字,即(IP地址:端口号)。也还应记住:同一个IP地址可以
有多个不同的TCP连接,而同一个端口号也可以出现在多个不同的TCP连接中。

可靠传输的工作原理

我们知道,TCP发送的报文段是交给IP层传送的。但IP层只能提供尽最大努力服务,也就是说,TCP下面的网络所提供的是不可靠的传输。因此,TCP必须采用适当的措施才能使得两个运输层之间的通信变得可靠。

我们可以使用一些可靠传输协议,当出现差错时让发送方重传出现差错的数据,同时在接收方来不及处理收到的数据时,及时告诉发送方适当降低发送数据的速度。这样一来,本来不可靠的传输信道就能够实现可靠传输了。下面从最简单的停止等待协议讲起。

停止等待协议

全双工通信的双方既是发送方也是接收方。下面为了讨论问题的方便,我们仅考虑A发送数据而B接收数据并发送确认。因此A叫做发送方,而B叫做接收方。因为这里是讨论可靠传输的原理,因此把传送的数据单元都称为分组,而并不考虑数据是在哪一个层次上传送的。“停止等待”就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。

  1. 无差错情况

    无差错情况
  2. 超时重传

    超时重传

    这里应注意以下三点:

    1. A在发送完一个分组后,必须暂时保留已发送的分组的副本(在发生超时重传时使用).只有在收到相应的确认后才能清除暂时保留的分组副本。
    2. 分组和确认分组都必须进行编号。这样才能明确是哪一个发送出去的分组收到了确认,而哪一个分组还没有收到确认。
    3. 超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些。
  3. 确认丢失和确认迟到

    超时重传

使用上述的确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信

像上述的这种可靠传输协议常称为自动重传请求ARQ (Automatic Repeat reQuest)。意思是重传的请求是自动进行的。接收方不需要请求发送方重传某个出错的分组。

  1. 信道利用率

    为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输(如下图所示)。流水线传输就是发送方可连续发送多个分组,不必每发完一个分组就停顿下来等待对方的确认。这样可使信道上一直有数据不间断地在传送。显然,这种传输方式可以获得很高的信道利用率。

    当使用流水线传输时,就要使用下面介绍的连续ARQ协议和滑动窗口协议。

连续ARQ协议

滑动窗口协议比较复杂,是TCP协议的精髓所在。这里先给出连续ARQ协议最基本的概念,但不涉及许多细节问题。详细的滑动窗口协议将在后面的5.6节中讨论。

下图(a)表示发送方维持的发送窗口,它的意义是:位于发送窗口内的5个分组都可连续发送出去,而不需要等待对方的确认。这样,信道利用率就提高了。分组发送是按照分组序号从小到大发送的。

连续ARQ协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。上图(b)表示发送方收到了对第1个分组的确认,于是把发送窗口向前移动一个分组的位置.如果原来已经发送了前5个分组,那么现在就可以发送窗口内的第6个分组了.

接收方一般都是采用累积确认的方式。这就是说,接收方不必对收到的分组逐个发送确认,而是在收到几个分组后,对按序到达的最后一个分组发送确认,这就表示:到这个分组为止的所有分组都己正确收到了。

但其缺点也在于此,如果传输过程中,中间某一分组丢失,那么,丢失分组后面的数据也都需重传。

在深入讨论TCP的可靠传输问题之前,必须先了解TCP的报文段首部的格式。

TCP报文段的首部格式

TCP虽然是面向字节流的,但TCP传送的数据单元却是报文段。一个TCP报文段分为首部和数据两部分,而TCP的全部功能都体现在它首部中各字段的作用。因此,只有弄清TCP首部各字段的作用才能掌握TCP的工作原理。下面讨论TCP报文段的首部格式。TCP报文段首部的前20个字节是固定的(如下图),后面有4n字节是根据需要而增加的选项((n是整数)。因此TCP首部的最小长度是20字节。

  1. 端口号:用来标识同一台计算机的不同的应用进程。TCP报头中的源端口号和目的端口号同IP数据报中的源IP与目的IP唯一确定一条TCP连接。

    1. 源端口:源端口和IP地址的作用是标识报文的返回地址。
    2. 目的端口:端口指明接收方计算机上的应用程序接口。
  2. 序号和确认号:是TCP可靠传输的关键部分。序号是本报文段发送的数据组的第一个字节的序号。

    在TCP传送的流中,每一个字节一个序号。e.g.一个报文段的序号为300,此报文段数据部分共有100字节,则下一个报文段的序号为400。所以序号确保了TCP传输的有序性。确认号,即ACK,指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当ACK标志为1时才有效。比如建立连接时,SYN报文的ACK标志位为0。

  3. 数据偏移/首部长度:4bits。

    由于首部可能含有可选项内容,因此TCP报头的长度是不确定的,报头不包含任何任选字段则长度为20字节,4位首部长度字段所能表示的最大值为1111,转化为10进制为15,15*32/8 = 60,故报头最大长度为60字节。首部长度也叫数据偏移,是因为首部长度实际上指示了数据区在报文段中的起始偏移值。

  4. 保留:为将来定义新的用途保留,现在一般置0。

  5. 控制位:URG ACK PSH RST SYN FIN,共6个,每一个标志位表示一个控制功能。

    1. URG:紧急指针标志,为1时表示紧急指针有效,为0则忽略紧急指针。
    2. ACK:确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段。
    3. PSH:push标志,为1表示是带有push标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队。
    4. RST:重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求。
    5. SYN:同步序号,用于建立连接过程,在连接请求中,SYN=1和ACK=0表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即SYN=1和ACK=1。
    6. FIN:finish标志,用于释放连接,为1时表示发送方已经没有数据发送了,即关闭本方数据流。
  6. 窗口:滑动窗口大小,用来告知发送方接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。窗口大小时一个16bit字段,因而窗口大小最大为65535。

  7. 校验和:奇偶校验,此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。

  8. 紧急指针:只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。

  9. 选项和填充:最常见的可选字段是最长报文大小,又称为MSS(Maximum Segment Size),每个连接方通常都在通信的第一个报文段(为建立连接而设置SYN标志为1的那个段)中指明这个选项,它表示本端所能接受的最大报文段的长度。选项长度不一定是32位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证TCP头是32的整数倍。

  10. 数据部分: TCP 报文段中的数据部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据。在处理超时的许多情况中,也会发送不带任何数据的报文段。

TCP可靠传输的实现

我们首先介绍以字节为单位的滑动窗口。为了讲述可靠传输原理的方便,我们假定数据传输只在一个方向进行,即A发送数据,B给出确认。这样的好处是使讨论限于两个窗口,即发送方A的发送窗口和接收方B的接收窗口。如果再考虑B也向A发送数据,那么还要增加A的接收窗口和B的发送窗口,这对讲述可靠传输的原理并没有多少帮助,反而会使问题更加繁琐。

以字节为单位的滑动窗口

耐心看完以下GIF,大概40S,就可以明白滑动窗口的机制。

下方为A发送方,上方为B接收方,透明方框为发送及接收窗口,变暗的球代表发送或接收过程中出现错误或丢失。

数据丢失或传输时间过长,会导致超时重传。

窗口大小是可变的。发送方的发送窗口不能超过接收方给出的接收窗口的数值。

超时重传时间的选择

上面已经提到过重传,这种重传的概念是很简单的,但重传时间的选择却是TCP最复杂的问题之一。

快了,频繁的重传可能是重复工作,无用却挤占信道;慢了,传输已经出了问题,发送方和接收方还在等。超时重传时间或大或小都会影响传输效率。但可以肯定的是:超时重传时间设置要比数据报往返时间(往返时间,简称RTT)长一点

简单来说,往返时间(RTT)指的其实是一个数据报发送到目的地,然后到发送方收到确认需要多少时间,这就是测量RTT。我们需要记住,发送的报文段和确认的报文并非是一一对应,也有可能是多个发送的报文对应一个确认报文。

注意:在 TCP 中,任何时刻只能有一个正在进行的RTT测量,一旦开始RTT测量,就不能再进行其他测量。

RTT是随着网络环境而动态变化的,也就是说每次测量RTT都可能有变化,就目前复杂的互联网环境来说,单次的测量RTT值无法被用于超时重传。因此tcp使用了一种加权平均往返时间 RTTSRTTRTTS(又称为平滑的往返时间,这里,我们把加权平均往返时间RTTs统一简称为RTTS,S表示Smoothed,因为进行的是加权平均,因此得出的结果更为平滑)。

第一次测量RTT时,RTTS就取所测量到的RTT样本值,即RTTS=RTT样本。以后每次测量到一个新的RTT样本,就按下面的公式重新计算一次RTTS
RTTS=(1α)×RTTS+α×RTT 新RTT_{S}=(1−α)×旧RTT_{S}+α×RTT
在上面的公式中 α 的取值为:0≤α≤1,RFC推荐的 α 值为1/8,即0.125。通过上面的公式得出的加权平均往返时间RTTS就比直接测量得出的RTT更加平滑,换句话说,新RTTS就是由7/8的旧RTTS和当前1/8的RTT(测量的新RTT样本)相加得出的。

值得注意的是,如果 α 的取值越小,那么RTTS更新相对较平稳;反之 α 的值越接近于1,则RTTS更新浮动较大。

RTT的计算只介绍到这里,其实还有更精确的计算方法,有兴趣可自行查阅。

选择确认SACK

可以看到上图中的重传使用了悲观的方式,如果第一个片段丢失而后面其他片段都接收到了,重传之后所有片段。

现在还有一个问题没有讨论。这就是若收到的报文段无差错,只是未按序号,中间还缺少一些序号的数据,那么能否设法只传送缺少的数据,而不重传已经正确到达接收方的数据?

答案是可以的。选择确认就是一种可行的处理方法。

选择确认SACK的前提是连接的两方设备必须同时支持这一功能,我们知道,TCP的首部没有哪个字段能够提供上述这些字节块的边界信息。RFC 2018规定,如果要使用选择确认SACK。那么在建立TCP连接时,就要在TCP首部的选项中加上“允许SACK”的选项,而双方必须都事先商定好。如果使用选择确认,那么原来首部中的“确认号字段”的用法仍然不变。只是以后在TCP报文段的首部中都增加了SACK选项,以便报告收到的不连续的字节块的边界

然而,SACK文档并没有指明发送方应当怎样响应SACK。因此大多数的实现还是重传所有未被确认的数据块。

流量控制

利用滑动窗口实现流量控制

一般说来,我们总是希望数据传输得更快一些。但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。所谓流量控制((flow control)就是让发送方的发送速率不要太快,要让接收方来得及接收

在连接建立时,接收方告诉了发送方,接收窗口大小为 400 字节。发送方发送了 400 字节的数据,但只收到接收方对前 200 字节数据的确认。发送方发送窗口还余 300 字节。

发送方收到了接收方对前 400 字节数据的确认。第一次发送完毕。但接收方仍通知发送方接收窗口为 400 字节,所以发送方必须把窗口减小到 400 字节。现在发送端最多可发送 400 字。

TCP的传输效率

如何控制TCP发送报文段的时机仍然是一个较为复杂的问题,这影响到TCP的传输效率。

前面已经讲过,应用进程把数据传送到TCP的发送缓存后,剩下的发送任务就由TCP来控制了。可以用不同的机制来控制TCP报文段的发送时机。例如,第一种机制是TCP维持一个变量,它等于最大报文段长度MSS。只要缓存中存放的数据达到MSS字节时,就组装成一个TCP报文段发送出去。第二种机制是由发送方的应用进程指明要求发送报文段,即TCP支持的推送(push)操作。第三种机制是发送方的一个计时器期限到了,这时就把当前已有的终存数据装入报文段(但长度不能韶过MSS)发送出去。

还有更好的方法,有兴趣可自行查阅。

TCP的拥塞控制

拥塞控制的一般原理

计算机网络中的链路容量(即带宽)、交换结点中的缓存和处理机等,都是网络的资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫做拥塞(congestion)

只加强某一个部分,效果不大。整个计算机网络是一个系统,可以比作一栋大厦,不光要地基,还需要材料、气候等等共同作用。问题的实质往往是整个系统的各个部分不匹配。只有所有的部分都平衡了,问题才会得到解决。

拥塞常常趋于恶化。如果一个路由器没有足够的缓存空间,它就会丢弃一些新到的分组。但当分组被丢弃时,发送这一分组的源点就会重传这一分组,甚至可能还要重传多次。这样会引起更多的分组流入网络和被网络中的路由器丢弃。可见拥塞引起的重传并不会缓解网络的拥塞,反而会加剧网络的拥塞。

拥塞控制与流量控制的关系密切,它们之间也存在着一些差别。所谓拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。但TCP连接的端点只要迟迟不能收到对方的确认信息,就猜想在当前网络中的某处很可能发生了拥塞,但这时却无法知道拥塞到底发生在网络的何处,也无法知道发生拥塞的具体原因。(是访问某个服务器的通信量过大?还是在某个地区出现自然灾害?)

相反,流里控制往往是指点对点通信量的控制,是个端到端的问题(接收端控制发送端)。流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收。

拥塞控制和流量控制之所以常常被弄混,是因为某些拥塞控制算法是向发送端发送控制报文,并告诉发送端,网络己出现麻烦,必须放慢发送速率。这点又和流量控制是很相似的。

进行拥塞控制需要付出代价。这首先需要获得网络内部流量分布的信息。在实施拥塞控制时,还需要在结点之间交换信息和各种命令,以便选择控制的策略和实施控制。这样就产生了额外开销。拥塞控制有时需要将一些资源(如缓存、带宽等)分配给个别用户(或一些类别的用户)单独使用,这样就使得网络资源不能更好地实现共享。十分明显,在设计拥塞控制策略时,必须全面衡量得失。

实践证明,拥塞控制是很难设计的,因为它是一个动态的(而不是静态的)问题。当前网络正朝着高速化的方向发展,这很容易出现缓存不够大而造成分组的丢失。但分组的丢失是网络发生拥塞的征兆而不是原因。在许多情况下,甚至正是拥塞控制机制本身成为引起网络性能恶化甚至发生死锁的原因。这点应特别引起重视。

从大的方面看,可以分为开环控制和闭环控制两种方法。

  1. 开环控制就是在设计网络时事先将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞。但一旦整个系统运行起来,就不再中途进行改正了。
  2. 闭环控制是基于反馈环路的概念:
    1. 监测网络系统以便检测到拥塞在何时、何处发生。
    2. 把拥塞发生的信息传送到可采取行动的地方。
    3. 调整网络系统的运行以解决出现的问题。

下面就来介绍更加具体的防止网络拥塞的方法。

TCP的拥塞控制方法

TCP进行拥塞控制的算法有四种,即慢开始(slow-start)拥塞避免(congestionavoidance)快重传(fast retransmit)快恢复(fast recovery)(见2009年9月公布的草案标准RFC 5681)。

详细的方法,有兴趣可自行查阅。

主动队列管理AQM

上一节讨论的TCP拥塞控制并没有和网络层采取的策略联系起来。

网络层的策略对TCP拥塞控制影响最大的就是路由器的分组丢弃策略。在最简单的情况下,路由器的队列通常都是按照**“先进先出”FIFO (First In First Out)的规则处理到来的分组。由于队列长度总是有限的,因此当队列己满时,以后再到达的所有分组(如果能够继续排队,这些分组都将排在队列的尾部)将都被丢弃。这就叫做尾部丢弃策略((tail-droppolicy)**。

有时候,若发生了路由器中的尾部丢弃,可能会同时影响到很多条TCP连接,结果使这许多TCP连接在同一时间突然都进入到慢开始状态。这在TCP的术语中称为全局同步((globalsyncronization)。全局同步使得全网的通信量突然下降了很多,而在网络恢复正常后,其通信量又突然增大很多。

了避免发生网络中的全局同步现象,在1998年提出了主动队列管理AQM (ActiveQueue Management)。所谓“主动”就是不要等到路由器的队列长度己经达到最大值时才不得不丢弃后面到达的分组。这样就太被动了。应当在队列长度达到某个值得警惕的数值时(即当网络拥塞有了某些拥塞征兆时),就主动丢弃到达的分组。这样就提醒了发送方放慢发送的速率,因而有可能使网络拥塞的程度减轻,甚至不出现网络拥塞。

AQM的实现方法,有兴趣可自行查阅。

TCP的连接管理

TCP是面向连接的协议。运输连接是用来传送TCP报文的。TCP运输连接的建立和释放是每一次面向连接的通信中必不可少的过程。因此,运输连接就有三个阶段,即:连接建立数据传送连接释放。运输连接的管理就是使运输连接的建立和释放都能正常地进行。

TCP连接的建立采用客户服务器方式。主动发起连接建立的应用进程叫做客户(Client)。而被动等待连接建立的应用进程叫做服务器(server)。

连接建立

连接建立。但更通俗的说法是三次握手,就好比两个人在街上隔着50米看见了对方,但是因为雾霾等原因不能100%确认,所以要通过招手的方式相互确定对方是否认识自己。

张三首先向李四招手syn(syn_sent),李四看到张三向自己招手后,向对方点了点头挤出了一个微笑ack。但是李四还有点狐疑,向四周看了一看,有没有可能张三是在看别人呢,他也需要确认一下。所以李四也向张三招了招手syn(syn_rcvd),张三看到李四向自己招手后知道对方是在寻求自己的确认,于是也点了点头挤出了微笑ack,李四看到对方的微笑后确认了张三就是在向自己打招呼established(连接建立)。于是两人加快步伐,走到了一起,相互拥抱。

其中李四连续进行了2个动作,先是点头微笑(回复对方),然后再次招手(寻求确认),实际上可以将这两个动作合一,招手的同时点头和微笑(syn + ack)。于是四个动作就简化成了三个动作。

syn_sentsyn_rcvd,这两个状态叫着「半打开」状态,就是向对方招手了,但是还没来得及看到对方的点头微笑。

数据传输

张三喊了一句话data,李四听见了之后要向张三回复自己听见了ack

至于可能出现的重传,前文已经介绍过了。

连接释放

连接建立。但更通俗的说法是四次挥手

TCP断开链接的过程和建立链接的过程比较类似,只不过中间的两部并不总是会合成一步走,所以它分成了4个动作,张三挥手fin——李四伤感地微笑ack——李四挥手fin——张三伤感地微笑ack

上面有一个非常特殊的状态time_wait,它是主动关闭的一方在回复完对方的挥手后进入的一个长期状态,这个状态标准的持续时间是4分钟,4分钟后才会进入到closed状态,释放套接字资源。不过在具体实现上这个时间是可以调整的。我把它比喻为犹豫再三的离别。

四次挥手也并不总是四次挥手,中间的两个动作有时候是可以合并一起进行的,这个时候就成了三次挥手,主动关闭方就会从fin_wait_1状态直接进入到time_wait状态,跳过了fin_wait_2状态。

TCP的有限状态机

为了更清晰地看出TCP连接的各种状态之间的关系,下图给出了TCP的有限状态机。图中每一个方框即TCP可能具有的状态。每个方框中的大写英文字符串是TCP标准所使用的TCP连接状态名。状态之间的箭头表示可能发生的状态变迁。箭头旁边的字,表明引起这种变迁的原因,或表明发生状态变迁后又出现什么动作。请注意图中有三种不同的箭头。粗实线箭头表示对客户进程的正常变迁。粗虚线箭头表示对服务器进程的正常变迁。另一种细线箭头表示异常变迁。

参考

  1. TCP报文格式详解——zzfx
  2. TCP动画
  3. 30-tcp可靠传输——超时重传时间——songly_
  4. TCP流量控制与拥塞控制——风轻云淡
  5. 跟着动画学习TCP三次握手和四次挥手——钱文品
posted @ 2018-11-05 00:08  夏洛克卷  阅读(629)  评论(0编辑  收藏  举报