计算机网络复习笔记 (第五章 传输层)
第5章 运输层
5.1 运输层协议概述
5.1.1 进程之间的通信
5.1.2 运输层的两个主要协议
5.1.3 运输层的端口
5.2 用户数据报协议UDP
5.2.1 UDP概述
5.2.2 UDP的首部格式
5.3 传输控制协议TCP概述
5.3.1 TCP最主要的特点
5.3.2 TCP的连接
5.4 可靠传输的工作原理
5.4.1 停止等待协议
5.4.2 连续ARQ协议
第5章 运输层
5.1 运输层协议概述
5.1.1 进程之间的通信
本节要点如下:
-
运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。
-
当网络的边缘部分中的两台主机使用网络的核心部分的功能进行端到端的通信时,只有主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时只会用到低三层的功能。
注:这一说法与1.7.5节讲述网络体系结构时给出的路由器连接TCP/IP网络的工作原理图是一致的。 -
运输层实现主机间进程也就是端到端的通信:IP数据报的首部明确地标志了通信的两台主机的IP地址,但真正进行通信的实体是主机中的进程,IP协议虽然能把分组送到目的主机,但是这个分组还停留在主机的网络层而没有交付主机中的应用进程。因此,我们需要在网络体系结构的网络层之上设计一个新的层,来支持主机进程间的通信,这个新的层就是运输层。这样的表述也就意味着,通信的真正端点并不是主机而是主机中的进程,因此运输层也被认为是实现端到端通信的网络体系结构层。
-
运输层的复用与分用功能:由于一台机器必须支持多个进程同时的运行和通信,运输层需要有一个很重要的功能,即复用(multiplexing)和分用(demultiplexing)功能。
在发送端,“复用”功能允许不同的应用进程都可以使用同一个运输层协议传送数据;
而在接收端,“分用”功能使得同一个运输层协议能够将收到的报文分发到对应的应用进程;
注:复用和分用针对的是同一个运输层协议,不同的运输层协议各自实现自己的复用和分用功能。
下图示意了运输层的两个协议,TCP和UDP,的复用和分用。 -
运输层提供应用进程间的逻辑通信:“逻辑通信”的意思是,从应用层来看,只要把应用层报文交给下面的运输层,运输层就负责把该报文传送到对方的运输层,好像这种通信就是两端的运输层沿水平方向直接传送数据。但事实上这两个运输层之间并没有一条水平方向的物理连接。
这种逻辑通信示意如下图。图中表明,应用进程“感觉”数据的传送是两端运输层协议直接完成的,但真正的数据传输是沿着图中的虚线方向进行的。
注:图中还示出了IP协议和运输层协议TCP和UDP的作用范围。
传输层对数据部分就进行了差错检测 所以好像不需要网络层对数据部分差错检测 只用检查ip数据报的首部就可以
5.1.2 运输层的两个主要协议
TCP/IP运输层包括两个主要的协议,即:
-
用户数据报协议UDP (User Datagram Protocol) [RFC 768]
-
传输控制协议TCP (Transmission Control Protocol) [RFC 793]
注:关于这两个协议后面将详细介绍。
5.1.3 运输层的端口
本节要点如下:
-
使用端口标识进程:运输层需要通过复用和分用实现多个应用进程间的通信,那么我们就需要一种方法来标识进程。这个方法称为协议端口号(protocol port number),或简称为端口(port)。端口号也可以理解为是运输层的“地址”。
注:之所以称为“协议”端口号,是因为通常一种应用进程会对应一个应用层协议。 -
端口号是16位的:TCP和UDP采用了二进制16位的端口号,其十进制范围是0~65535,十六进制范围是0x0000~0xFFFF。
-
端口号的分类:
-
服务器端使用的端口号:服务器端实现的一个应用层协议需要公开声明其端口号,以便客户端访问,它又分为两种情况,
-
熟知端口号(well-known port number)或系统端口号,它是数值范围为0~1023的端口号。
它们是由IANA(The Internet Assigned Numbers Authority,互联网数字分配机构)指派的一些典型的应用层协议,如表5-2所示。下图给出了形象的示意:
注:TCP与UDP协议各自有独立的端口号。 -
登记端口号,即数值范围在1024~49151之间的端口号。这类端口号是为没有熟知端口号的应用程序使用的。
注:尽管使用这类端口号的标准方法是在IANA按照规定的手续登记,以防止重复,但实际也不尽然。许多用户经常自行配置使用。 -
客户端使用的端口号:其数值范围为49152~65535。 这类端口号在客户进程运行时自动动态选择,因此又叫做短暂端口号。
当服务器进程收到客户进程的TCP/UDP报文时,就能从报文的首部的源端口号获知客户端进程所使用的端口号,因而就能以该源端口号构造应答报文的目的端口号,就如同以收到IP地址中的源IP地址作为应答报文的目的IP地址一样。
常见端口号:
5.2 用户数据报协议UDP
5.2.1 UDP概述
用户数据报协议UDP (User Datagram Protocol)仅提供了最小功能的运输层服务,包括:
-
复用和分用:通过端口号实现到使用UDP协议的应用层进程或协议的复用和分用。
-
差错检测:实现对包括首部和数据部分的整个报文的差错检测,这一举措增强了数据的可靠性验证,因为IP层只针对IP首部进行差错检测。
由于UDP只提供了上述最小功能的运输层服务,使得它具有如下特点:
-
UDP是无连接的:即发送数据之前不需要建立连接(当然,发送数据结束时也没有连接可释放),因此减少了开销和发送数据之前的时延。
-
UDP使用尽最大努力交付:即不保证可靠交付,也就是说它只是保持了IP的尽最大努力交付服务,没有进一步的交付保证。
-
UDP是面向报文的:发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并也不拆分,而是保留这些报文的数据边界。在接收方,UDP对IP层交上来的UDP用户数据报,在去除首部后就原封不动地交付到上层的应用进程。因此,应用程序必须选择合适大小的报文,以尽量确保对应的IP数据报可以封装到一个数据链路层的帧中,从而避免IP层在传送时的分片和重装,以使IP层具有较高的效率。
-
UDP没有拥塞控制:因此网络出现的拥塞不会使源主机的发送速率降低。这一特点使得它适合于要求源主机以恒定速率发送数据的实时应用(如语音通信、实时视频会议等),这些应用允许在网络发生拥塞时丢失一些数据,但却不允许数据有太大的时延。所以很适合一些实时应用。所以有时候丢一点是可以的 所以传输不可靠啊
-
UDP的首部开销小:UDP首部只有8个字节,比TCP的20个字节的首部要短得多,因而使用UDP传输开销很小,可以获得更好的网络吞吐量。
5.2.2 UDP的首部格式
UDP报文的首部格式如下图所示,它只包括4个字段,共8个字节。
其中的长度为包括首部和数据的整个报文的长度,最小值是8,即没有数据的情况。
|
应用层给udp多长的报文 udp就保留边界加个首部封装罢了
如果这个报文长度过大 下行到数据链路层有MTU要求 这样网络层不得不分片重装 而如果长度过小 首部就比报文相对更大 这样会影响传输效率 所以报文长度要适当
UDP数据报的差错检测
UDP数据报使用了与IP首部相同的差错检测算法,即反码算术运算差错检测算法。
但要注意的是,UDP在计算差错检测的检验和时,增加了伪首部数据,如下图所示:
注意1:
-
伪首部只用于进行差错检测计算,不在网络中传输。
-
伪首部共有12个字节,其中
-
源和目的IP分别占4字节。
-
最后的4个字节中,
-
第1个字节为0,
-
第2个字节为IP中的UDP协议号,即十进制的17,
-
第3-4字节为UDP报文的总长度,它与UDP报文首部中的长度值相同。
注意2:如果UDP的数据部分为奇数个字节,则在计算检验和时需要在最后填充一个值为0的字节。因为所使用的反码算术运算差错检测算法要求以2字节为单位进行计算。
如,在下面的例子中,UDP数据报的长度是15字节,因而数据部分有7个字节,于是在计算检验和时就需要在最后填充一个0字节。
发送端和接收端是不一样的 接收端就得知发送端填充的校验和了 所以要把本来全为0的校验和也参与运算
5.3 传输控制协议TCP概述
5.3.1 TCP最主要的特点
TCP在实现基本的运输层功能,即复用/分用和差错检测的基础上,实现了一些非常重要的功能,这使它成为了一个极其强大的运输层协议。
我们可以用一句话较全面地概括TCP的特点:TCP是一个可靠的、面向连接的、带有流量控制和拥塞控制的全双工运输层协议。
相对于UDP数据报面向报文的特点,TCP是面向字节流的。
下面的两个图解释了TCP面向字节流的特点:
-
在发送端,TCP提供了发送缓存来暂存应用进程交付的数据,TCP按照自己的策略对发送缓存中的数据构造TCP报文向网络层交付,这使得TCP发送的数据块与应用层交付的数据块相互独立。
-
在接收端,TCP提供了接收缓存来暂存TCP收到的数据,接收端应用进程从TCP接收缓存获取数据的分块和速率也与TCP接收数据块的大小和速率相互独立。
5.3.2 TCP的连接
一个TCP连接涉及到通信的两个端点,如下图所示:
TCP连接的一端由端系统的IP地址和端口号唯一确定,这两个数字合起来常称为套接字 (socket) 或插口,常以如下方式表示:
套接字 socket ::= (IP地址 : 端口号) ,如:套接字 socket = (200.200.200.200 : 80)
这样一个TCP连接就可以由两个套接字唯一地表示:
TCP 连接 ::= {socket1, socket2} = {(IP1: port1),(IP2: port2)}
TCP 连接 = {(100.100.100.100: 49152),(200.200.200.200 : 80)}
注:上述的符号“::=”意为“定义为”。
5.4 可靠传输的工作原理
假如传输信道是理想的,即满足如下条件:
-
信道不产生差错。
-
不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据。
在这样的理想信道条件下,不需要采取任何措施就能够实现可靠传输。
然而,实际的传输信道不可能具备以上两个理想条件。IP层仅提供“尽力传递”服务,也就是说,IP层不能保证报文正确、及时、按序地交付到目的主机,也就是IP层不能保证可靠传输。尽管像视频、语音类的通信允许存在一定程度的传输差错或丢包,但是,我们绝大部分时候却需要可靠传输。
于是,我们需要对TCP协议进行聪明的设计,以实现在不可靠IP层上的可靠传输层服务。
5.4.1 停止等待协议
可靠传输的基本思想是:确认+重传。
即,发送端对于每个发送的报文都需要接收端发回确认报文,如果在给定的时间内没有收到确认报文,则即重传该报文。
要实现“确认+重传”的可靠传输,需要一些必须的辅助要素,包括:报文的缓存、报文的编号、以及超时计时器等。
我们先用简单的停止等待(stop-and-wait)协议,简称为停等协议,来说明可靠传输的基本思想。
停等协议有如其名:发送端每发送完一个报文,就停下来等待接收端的确认,如果接收端确认到了,再发送下一个报文。
注:确认报文简称为ACK,来自于确认英文单词acknoledgement的前3个字母。
如果停等协议正常执行,则情况将如下图所示:
注:我们遵循了计算机中编号从0开始的规范,但要到稍后才会说明为什么要对报文编号。
然而,传输的分组可能会出现两个问题:
-
出现差错,即接收端收到了分组,但是差错检测检验未通过;
-
传输的分组在途中丢失,未到达接收端。
在这两种情况下,接收端都不可能向发送端发回ACK。
发送端需要采取机制,判断接收端没有及时发回ACK,这种机制就是超时计时器(time-out timer)。
发送端发送出去报文后,就启动一个超时计时器(通常为倒计时计时器),如果超时计时器时间到了(即减到0),发送端没有收到ACK,则发送端就重传此前发送的分组。如下图所示。
注:超时计时器的时间通常取为比往返时间RTT稍大一些的时间,这样就可以保证在ACK报文正常到达前不会重传。其实超时计时器时间的选取是一个很复杂的问题,我们将在5.6.2节介绍一种自适应的TCP超时计时器选取方法。
而为了能够重传,发送端发送出去报文后,就不能将该报文清除,而是要将该报文缓存起来,以便重传。
还有一种发送端收不到ACK的情况,即接收端正常收到了报文,且正常发送了ACK,但是ACK在传输过程中丢失了。这种情况下,发送端也将会因为超时计时器时间到而进行报文重传。如下图所示。
然而,这种情况下,接收端会收到重复的报文。要使传输可靠,接收端就应该有机制判断出来一个报文是重复的报文还是新的报文。这种机制就是报文编号。有了报文编号,接收端就可以通过编号判断出收到的报文是新的还是重复的,如果是重复的,它就将该报文抛弃,但还是要发出确认号,因为发送端发送了重复报文后,会继续等待对重复报文的确认。
对于停等协议来说,报文编号只要使用一位二进制数字,即交替使用0号报文和1号报文,就可以了。
以期望收到的报文序号为确认号的机制
上面的ACK机制是接收端收到什么编号的报文,就对什么编号的报文进行确认。实际可靠传输协议中使用了更为科学的ACK确认号机制,即确认报文中携带“期望接下来收到的报文序号(expected datagram sequence number)”。在该机制下,接收端会维护一个期望接下来要收到的报文编号,当该编号的报文收到后,它就更新期望的编号,并以ACK报文告诉发送端接下来该发送的报文号。
在以期望收到的报文序号为确认号的机制下,接收端需要设置一个期望接收的报文编号的状态。在此机制下,前述的各种情况可重述如下:
-
正常情况
-
收到有差错报文的情况
-
报文丢失的情况
-
确认丢失的情况
确认迟到的情况
下面我们专门研究确认迟到的情况,即某个较早时刻的确认报文在较晚时刻确认报文之后到达发送端的情况。
经过分析,确认迟到共有三种情况:
-
情况1:先于相同编号的确认报文到达,这时会提前发送期望的报文,但协议仍然会正确工作,即使相同编号的确认报文丢失,协议也会正确工作。
-
情况2:先于不同编号的确认报文到达,这时只要抛弃迟到的确认,上述协议仍然会正确工作。
-
情况3:后续相同编号的报文丢失,但对应编号的早期的确认报文却延迟到达,这种情况下协议会失败。
注:后面我们将会看到,TCP的可靠传输实现中使用了32位的报文首字节数据编号,由于32位编号空间非常大,使得发生上述第3种情况成为不可能,因而避免了协议的失败。
自动重传请求ARQ
上述的停等协议设计完成后就会在通信的两端自动运行,即重传的请求是自动进行的,因而这种可靠传输协议常称为自动重传请求ARQ (Automatic Repeat reQuest)协议。
停等协议是一个效率很低的协议
直觉告诉我们,停等协议是一个效率很低的协议。
这种低效率我们可以用形式化的方法表达一下。
我们将前述的图横过来画成下面的样子,并为各部分标上时间符号,就可以得到如下所示的信道利用率公式:
上述公式中,为报文的发送时延,RTT为发送端和接收端间的往返时间,为确认报文的发送时延。
利用率计算公式的由来是:在的时间里只有的时间里在传输有效的数据,因而信道利用率就是和之间的比值。
教材P216页上部给出了信道利用率的实际计算例子。
流水线传输
为解决停等协议的效率问题,人们提出了流水线式的传输方式。
其基本思路是:发送方连续地发送报文,接收方每收到一个报文就发回一个确认,如果报文没有差错、不丢失、确认也不丢失、确认也不延迟到达,则这种方式就会有形如下图的传输过程。
显然,在这种理想状态下,信道利用率可以达到100%。
然而,这种理想情况几乎是不存在的:报文可能会出现差错、可能会丢失、确认也可能会丢失、确认也可能会延迟到达。
为此,可行的流水线传输方式还需要进行仔细的设计,以解决这些情况。下面的连续ARQ协议就是一个较实际也是较好的解决方案。
5.4.2 连续ARQ协议
本节要点如下:
-
滑动窗口协议和连续ARQ协议之间的关系:连续ARQ协议以滑动窗口协议为基础。
-
滑动窗口协议:滑动窗口协议的关键是在发送端设置一个待发送报文的窗口,窗口内的报文可以以流水线方式连续地发送出去,而不必等待单个报文的确认。如下图所示。
当第1个报文的确认到达后,窗口就向前滑动一个报文,这样进入窗口的新的报文就可以发送出去,不必等到它前面报文确认的到来。
注:为提高效率,接收端常采用累积确认的方式,即收到一个报文后不是立即发送确认,而是等待一小段时间,这样如果收到连续到达的报文,就只发送最后一个报文的确认,接收端据此判断此前的报文均已全部收到。上面的图(c)就示意了这种情况,接收端发回对4号报文的确认,发送端据此判断,4号报文及其前面的报文均已收到,于是将窗口向前滑动3个报文,从而使得7、8、9号报文进入窗口,因而可以连续地发送出去。 -
连续ARQ协议:连续ARQ协议指的是基于滑动窗口协议的自动重传请求协议,即在滑动窗口协议的基础上,当出现报文差错、报文丢失、确认丢失等情况时,实现自动重传的机制。
-
GBN协议:连续ARQ中的一种协议是GBN(Go-Back-N, 回退N)协议。首先连续ARQ为每个发出的报文设置超时计时器,当遇到报文差错、报文丢失、确认丢失时,该报文相应的超时计时器就会超时,GBN的处理方法是:重新将窗口中出现超时的报文到窗口最后的报文全部依次重传。
第5章 运输层
5.5 TCP报文段的首部格式
5.6 TCP可靠传输的实现
5.6.1 以字节为单位的滑动窗口
5.6.2 超时重传时间的选择
5.6.3 选择确认SACK
5.5 TCP报文段的首部格式
TCP的PDU称为报文段(segment),其格式如下图所示:
教材P217-221页对TCP报文段进行了全面和详细的解释
下面对给出一些补充性的要点解释:
-
TCP报文段首部也分成固定部分和可变部分。其中固定部分为20字节,可变部分长度在0~40字节之间,且必须是4的整数倍。
-
关于序号:
-
TCP报文段序号是其中的数据在整个发送过程中的字节顺序号,这一点与此前介绍可靠传输原理时将整个报文进行顺序编号是不同的,但不会影响可靠传输机制。这一点也呼应了此前关于TCP协议是面向字节流的说法。
-
报文段序号占4字节,因而序号范围是,即0~4,294,967,295,共(大约)个编号。
-
当TCP建立连接时,通信的两端会各自在范围内随机选择一个序号作为本次通信的第一个字节的序号。
-
此后,TCP循环使用之间的编号,为实现此目的,TCP使用MOD 的运算计算下一个报文的序号。
注:MOD运算为取模运算,简单的理解即是针对某个除数的除法运算的余数。一般地,MOD N运算的结果范围是0~N-1。因此MOD 运算的结果范围将会是0~。
假设当前TCP报文的编号(即数据部分第1个字节的编号)为,当前报文共有字节的数据,则下一个报文的编号将会是:。
例如:假设发送端A当前TCP报文段序号为,该报文有字节,则下一个报文段的序号为;假设中含有13个字节,则下一个报文段的序号将会是。 -
关于确认号:
-
首先确认号是对已经接收到的对方报文(即数据)的确认,因而确认号是与对方的序号有关的,而序号是本方的报文序号,鉴于通信的双方各自取随机的0~之间的数作为初始的报文序号,这两个序号从数值上是没有任何关系的。
-
只有当下面的控制位中的ACK=1时,报文中的确认号才有效。
-
确认号可以在正常发送数据时携带,不一定单独发送,这种方法叫做捎带确认(piggy-back),显然捎带确认可以提高传输的效率。
-
TCP确认号也是采用“期望接下来接收的报文序号”(expected sequence number)机制。因此针对上面的例子,接收端B收到A发送来的报文后,发送的确认号将是,语义是“我接下来希望接收序号为4,294,967,292的报文”。
-
TCP的确认也将是累积的。如在上述的例子中,接收端B收到报文后,可能不立即发送确认,而是等收到后再发送确认,这时的确认号就会是。发送方收到确认号为10的报文后,就会认为所发送的编号到之间的25个数据字节均被发送方正常收到了,接下来可以从编号为的字节开始发送数据。
-
由于4字节0~的编号范围足够的大,不用担心因编号绕回而带来的协议错误。
-
关于数据偏移:
-
“数据偏移”的直观意思是报文中数据开始的位置,而数据开始前的部分为报文的首部,因而“数据偏移”也就是首部长度。
-
“数据偏移”与IP数据报中的“首部长度”非常相似,都是4个二进制数据位,都是以4字节为单位的。因而首部只有固定部分的20字节时,数据偏移的值将会是5(0101)。由于数据偏移的最大值是1111,即15,因而首部最多可以有60个字节,即首部的可变部分最多可以有40个字节。又因为数据偏移是以4字节为单位的,可变部分如果有,长度必须是4的整数倍,如果实际不是4的整数倍,则需要填充到4的整数倍。
-
关于控制位:报文结构中列出了6个控制位,其中特别需要掌握的控制位如下,
-
ACK(ACKnoldegement,确认)控制位:用来说明确认号有效的;
-
SYN(Synchronization,同步)控制位:用来建立连接的;
-
FIN(FINish,结束)控制位:用来关闭(也称为释放)连接的;
-
RST(ReSeT,重置)控制位:用来重置连接的,也能关闭连接。
-
关于窗口:窗口是用于进行流量控制的,我们将在5.7节流量控制中详细解释。
-
关于检验和:
-
检验和是用来对整个报文进行差错检测的;
-
使用的算法与IP数据报首部和UDP相同,即反码算术运算差错检测算法;
3.与UDP检验和计算一样,在计算检验和时,也要给报文加上12字节的伪首部。 第四个字段协议号为6 而UDP的是17
TCP报文段中的选项
TCP协议允许使用报文段首部的可变部分来为通信设置选项。
TCP的选项分成两类:
-
一类是单字节的,该字节中的值说明选项的类型(kind)。
-
另一类是多字节的,它由1字节的类型、1字节的总选项长度和0或多字节的数据部分组成,如下图所示。参见TCP Options。
常见的TCP选项:
-
Kind=0:选项列表结束(End of option list)选项。(注:该选项实际中几乎没有实现和使用)。
-
Kind=1:无操作(No-Operation)选项,用于填充以保证4字节边界。
-
Kind=2:最大报文段长度(Maximum Segment Size, MSS)选项,用于设定TCP报文段的最大数据量,对于数据链路层为以太网的情况,该值通常为1460(0x05B4)。
-
Kind=3:窗口比例因子(Window Scale Factor)选项。报文段中用于进行流量控制的“窗口”项是一个2字节16位的值,数值范围为0~,即最大不超过64K字节。要使用更大的窗口就需要设置窗口比例因子选项,该选项给出了窗口数值向左移位的量,即实际窗口的大小为“窗口”中值乘以,其中f为窗口比例因子的数值。标准规定,f应取0~14之间的值。
-
Kind=4:允许选择重传(SACK Permitted)选项。此选项将在5.6节TCP可靠传输中说明。
-
Kind=5:选择重传(Selective ACK,SACK)选项。此选项将在5.6节TCP可靠传输中说明。
-
Kind=8:时间戳(Time Stamp)选项。这是一个10字节的选项,用于实现如下两项功能:
-
用来计算往返时间RTT。发送方在发送报文段时把当前时钟的时间值放入时间戳(TimeStamp)字段,接收方在确认该报文段时把时间戳字段值复制到时间戳回送回答(TimeStamp Echo Reply)字段。这样,发送方在收到确认报文后,就可以准确地计算出RTT来。
-
用于处理TCP序号超过 的情况,这又称为防止序号绕回PAWS (Protect Against Wrapped Sequence numbers)。 前已述及,TCP 报文段的序设计为4字节32位的数,一个序号在发送完字节的数据后,就会被重复,这在速率不是很高的网络中不成问题,例如对于1.5Mbps的网络,序号重复需要6小时以上,但是对于高速的2.5Gbps的网络,则不到14秒钟就会重复。为了使接收方能够把新的报文段和迟到很久的报文段区分开,可以通过在报文段中增加时间戳选项的方法来辅助。
5.6 TCP可靠传输的实现
本节讨论TCP协议中可靠传输的具体实现方法。为方便讨论,假定数据传输只在一个方向进行,即A向B发送数据,而B发回确认。这样就可以将问题简化为只考虑两个窗口,即A的发送窗口和B的接收窗口。
因为网络层是尽最大努力交付 所以并不可靠 在其上层的传输层就要保证这种可靠性。如果是UDP协议 仍是需要应用层来保证可靠性。
tcp步骤是 校验 序号 确认 重传
5.6.1 以字节为单位的滑动窗口
注意1:这里说的以字节为单位的滑动窗口并不是说TCP一次一个字节地发送数据,而是说TCP的报文以其中数据第一个字节的序号进行编号,而不是以整个报文为单位进行编号。如,当前报文的编号为100,说明当前报文的数据的第一个字节的编号是100,如果该报文中包含50个字节的数据,则下一个报文的编号将会是100+50=150,而不是100+1=101,因为其中第一个数据字节的编号为150。
注意2:教材以类似如下的图示说明TCP的以字节为单位的滑动窗口,
-
但不要被此误导:
-
首先不要认为发送端将31-41之间的数据一个字节一个字节地发送出去,尽管有时一个TCP报文段会仅携带一个字节的数据;
-
其次不要认为发送端用一个报文将31-41之间的数据发送出去,而接收端可能会收到其中的31号、34号、35号字节,而丢失32号、33号字节。
-
正确的理解是:发送端将数据组织到TCP报文段中,一个报文段一个报文段地发送,而接收端或者完整地收到一个报文段,或者完全收不到一个报文段,特别是可能不会连续地收到报文段。
为了更加清楚正确地表达TCP以字节为单位的滑动窗口,我们将上面的图示进行了一些调整,并以如下所示的要点描述TCP的以字节为单位的滑动窗口机制:
-
假设以A作为发送端、B作为接收端建立了TCP连接,在连接建立阶段,B向A报告的窗口大小为20字节,则A端建立20字节的发送缓存,B端建立20字节的接收缓存。如下图所示。A端基于连续ARQ协议,连续地发送了4个报文段,分别是包括第31、32共2字节的31号报文段,包括第33~35共3字节的33号报文段,包括第36~39共4字节的36号报文段,和包括第40、41共2字节的40号报文段。发送了这些报文后,根据连续ARQ协议,A端会为每个报文启动一个超时计时器。而且,A端的发送窗口变为以三个参量描述的状态,其中,~(不含)为整个发送窗口,~(不含)间为已发送出去但正在等待确认的数据,而~(不含)间为可以发送的数据。
-
假设B收到了第31号报文,则因为该报文包括两个字节,它会将接收窗口向前移动2个字节,并且向A发回确认,确认号为33,表示它希望接下来接收第33号字节开始的数据。
-
A收到B发来的33号确认后,就会认为33号字节之前的数据(不包括33号)均已正常收到,于是,它将发送窗口向前移动两个字节,使第51、52号字节的数据成为可以发送出去的数据。同时将变量的值均增加2,但保持的值不变(假定没有再发送TCP报文段)。
-
假设,在下一时刻,B端接收到了不连续的36号报文,则它将保持接收窗口不变,但要向A发送对编号33的确认,注意不是对编号40的确认,以告知发送方33号报文仍然未收到。
-
A端收到对33号的重复确认时(注意上面的第2步中A端已经接收到过一次对33号报文的确认),或者33号报文的超时计时器时间到了时,会立即重发33号报文。
-
B端收到A端重发的33号报文后,会根据累积确认的规则,向A端发送对40号报文的确认,同时将当前接收窗口的左边界移动到40的位置上。
-
A端收到对40号报文的确认后,也将当前发送窗口的左边界移动到40的位置上。
缓存与窗口
TCP要实现可靠通信,需要在两端设置缓存与窗口,在这里我们说明缓存与窗口的关系。
缓存是在TCP连接建立时确定的,它是计算机存储器中一段固定的存储空间,在一次TCP连接有效的期间内不会变化。而窗口则是缓存中的一部分,它是滑动的,在TCP运行期间会频繁地变化。
特别需要注意的是:缓存和窗口都是以循环方式使用的,而实现循环的方法就是前述的求模运算(即MOD运算)。
发送缓存与发送窗口
下图示出了发送缓存与发送窗口的一般情况。
图中,~之间为发送缓存,它是内存中一块固定的存储空间。
~之间为发送窗口,也是最新的确认号;~之间为已经发送但等待确认的数据;~之间为可以发送但尚未发送的数据;为发送端应用进程写入发送缓存的最后一个字节。
注意:的位置也可能会出现在~之间,表示发送方应用进程写入的数据不满发送窗口的情况,这时可以发送但尚未发送的数据就只能是~之间的数据。
发送缓存中的数据与发送窗口也可能会出现在发送缓存中绕回的情况,如下图所示。
这时,尽管的数值比都大,~之间仍然为发送窗口,但要注意是绕回意义上的发送窗口,仍然是最新的确认号;~之间仍然为已经发送但等待确认的数据;~之间仍然为可以发送但尚未发送的数据;仍然为发送端应用进程写入发送缓存的最后一个字节。
注:处理“绕回”问题的计算方法是求模运算(即MOD运算)。
接收缓存与接收窗口
下图示出了接收缓存与接收窗口的一般情况。
图中,~之间为接收缓存,它是内存中一块固定的存储空间。
~之间为接收窗口;为接收应用进程接下来要取的数据;~之间为按序收到的已经确认的数据;是最新的确认号;为未按序到达的数据。
接收缓存中的数据与接收窗口也可能会出现在接收缓存中绕回的情况,如下图所示。
这时,尽管的数值比大,~之间仍然为接收窗口,但要注意是绕回意义上的接收窗口,仍然是最新的确认号;为接收应用进程接下来要取的数据;~之间为按序收到的已经确认的数据;为未按序到达的数据。
注:处理“绕回”问题的计算方法是求模运算(即MOD运算)。
5.6.2 超时重传时间的选择
TCP的发送方在规定的时间内没有收到确认就会因为超时而重传已发送的报文段。这种重传的概念是很简单的,但重传的超时时间的选择却是TCP最复杂的问题之一。这是因为:
-
如果把超时重传时间设置得太短,就会引起很多报文段的不必要重传,使网络负荷增大。
-
但若把超时重传时间设置得过长,则又会使网络的空闲时间增大,引致传输效率的降低。
一个比较合理的选择是使超时时间比通信两端的往返时间RTT稍大一些。然而要将这个想法落地还需要解决很实际的问题:
-
RTT是一个随机性很大的量,因为TCP下面的IP互联网层是一个尽力传递的服务层,携带TCP报文段的IP数据报可能只经过一个高速率的局域网,也可能经过多个低速率的网络,并且每个IP数据报所选择的路由很可能不同,这就会造成RTT是一个随时间不断变化甚至变化很大的量,如下图中的Sample-RTT(即样本RTT)所示。
为避免直接使用样本RTT而带来的超时计时器时间“过山车”式的剧烈变化,我们需要有一种平滑机制来获得依赖于样本RTT但又平缓变化的RTT估计,如上图中的Estimated RTT所示。 -
“使超时时间比通信两端的往返时间RTT稍大一些”是一个很好的注意,但大多少呢?这也需要有切实可行的计算方法。
滑动加权平均法计算重传超时时间RTO(Retransmission Time-Out)
要获得RTT估计,首先需要获得样本RTT,或瞬时RTT,这是通过测量一个TCP报文段从发出到收到确认的时间间隔来获得的。
为了获得平滑的RTT估计,TCP采用了一种加权平均计算方法。该计算方法包括三个组成部分:
-
以滑动加权平均法计算RTT的估计值。该方法包括两个步骤:
-
开始时刻测量一次样本RTT值(通常是建立连接的握手阶段测量的值),并直接用作为首次的估计值,即:
-
此后每当测量一次RTT的样本值,就用下式计算RTT的估计值:
, -
说明:
-
与教材不同,我们用RTTS表示样本RTT,其中S来自于样本的英文Sample;我们用RTTE表示估计的RTT,其中E来自于估计的英文Estimate。
-
当时,估计的RTT由上一轮估计的RTT和本轮测量得到的RTT以因子加权平均得到。RFC 6298推荐的值为,即0.125,也就是估计的RTT更多地依赖于上一轮估计的RTT,测量的样本RTT在估计的RTT中占比很低,因而估计的RTT会比样本RTT要平滑得多。
-
以RTT估计值RTTE和RTT偏差的估计值RTTDE计算重传超时时间RTO。RFC 6298建议以下式计算重传超时时间RTO:
确切地说应该是:,
即,RTO的值取比估计的RTT值大出4倍的RTT偏差估计值。 -
RTT的偏差RTTD(字母D来自于偏差的英文Deviation)也以滑动加权平均法计算估计值。该方法同样包括两个步骤:
-
开始时刻测量一次样本RTT值(通常是建立连接的握手阶段测量的值),并用的一半作为RTTD的首次估计值,即:
-
此后每当测量一次RTT的样本值,就用下式计算RTTD的估计值:
,
其中为绝对值。 -
说明:推荐的值为,即0.25,也就是估计的RTTD更多地依赖于上一轮估计的RTTD,样本偏差在估计的RTTDE中占比很低,因而估计的RTTDE会比样本偏差要平滑得多。
重传报文RTT的计算—Karn算法
重传报文RTT测量可能不准确的问题:在5.4节可靠传输原理中曾经介绍过,重传报文可能会出现确认迟到问题,如下图所示。图中A端收到第一个ACK1时,无法判断是首次发送还是重传的的ACK,这就造成了该次ACK测量的不准确问题。
下图从另一个角度说明了以重传报文的ACK测量RTT所带来的问题。
Karn针对此问题提出了一个想法,称为Karn算法:在计算加权平均的RTT时,只要报文段重传.了,就不采用其往返时间样本。这样得出的加权平均RTTE和RTO就去除了重传报文ACK的不确定性问题,使得计算更准确了一些。
Karn算法带来的问题:然而,此Karn算法又会引起新的问题。如果因网络拥塞的原因导致报文段的时延突然增大了很多,则在原来得出的重传时间内,不会收到确认报文段。于是就重传报文段。但根据Karn算法,不会考虑重传报文段的往返时间样本。这样,超时重传时间就无法及时更新以适应网络的变化,导致过多的重传,从而降低了网络的效率和吞吐量。
为此,提出了Karm算法的修正算法:报文段每重传一次,就把超时重传时间RTO增大一些。典型的做法是取新的重传时间为旧的重传时间的2倍。当不再发生报文段的重传时,再根据上面给出的滑动加权平均法计算超时重传时间。实践证明,这种策略较为合理和有效。
5.6.3 选择确认SACK
前已述及,TCP接收端在收到不连续的报文段时,会将不连续的报文段保存下来,并发送迄今为止连续收到字节流的下一个期望接收到的字节号。
如下图所示,当36号报文早于33号报文收到时,接收端会将36号报文保存下来,但发送对33号报文的确认。
一个更具代表性的情况如下图所示,当前连续收到数据的下一个字节号是1001,但后面又收到了不连续的1501~3000和3501~4500字节,按照前述的确认发送机制,收到1501号和3501号报文后,都要发送对1001的确认,那么发送端收到对1001的重复确认后,接下来该怎样发送呢?
如果按照前述的GBN策略,则发送端要从1001开始重传后面所有已经发送过的数据。然而这存在传输效率问题,因为1501号和3501号报文已经被接收端收到了。
TCP以SACK(Selective ACK,选择确认)机制为这一问题提供了很好的解决方案。
TCP的SACK机制分成两个组成部分:
-
在TCP连接建立阶段,双方使用Kind=4的允许选择重传(SACK Permitted)选项协商双方启用SACK机制,该选项只有类型Kind和长度Length2个字段共2个字节,没有数据部分。
-
在数据传输阶段,TCP使用下图所示的Kind=5的SACK选项报告未按序收到的数据块。该选项中的数据部分以块首字节号、块尾字节号的方式报告接收方未按序收到的连续数据块,其中块首字节号和块尾字节号均为4字节长,即每个块要占8个字节。由于TCP选项部分最多40个字节,因而一个TCP报文段的SACK选项最多可以说明4个数据块,这时该SACK选项的长度将是34字节。
例:当接收端收到如下图所示的不连续的数据块时,它发回的TCP报文段的确认号将会是1001(ACK控制位置1)。其SACK选项将是18字节长,其中包括两个已收到的不连续数据块的说明,分别对应首尾字节号1501~3000和3501~4500。
5.7 TCP的流量控制
5.7.1 利用滑动窗口实现流量控制
5.8 TCP的拥塞控制
5.8.1 拥塞控制的一般原理
5.8.2 TCP的拥塞控制方法
5.9 TCP的运输连接管理
5.9.1 TCP的连接建立
5.9.2 TCP的连接释放
5.7 TCP的流量控制
流量控制(flow control)的定义:流量控制指的是控制发送方的数据发送速率,使得接收端能够容纳得下发送端发来的数据流。流量控制只涉及一个TCP通信的两端。
TCP采用的流量控制策略:TCP采用了接收端控制的流量控制策略,即让接收端告知发送端其当前可以接收的最大数据容量,这样发送端只要发送的数据不超过该最大容量,接收端就一定能接收得了发送端发来的数据。
TCP采用的流量控制方法:TCP通过让接收端在发回的TCP报文段中用窗口字段声明其接收缓存剩余量的方法来具体地实现流量控制。
注意:TCP的流控窗口值也是捎带报告的。
由于窗口字段只有16位长,即窗口最大为字节,也就是64K-1字节,这个值还是偏小。为此,TCP提供了窗口比例因子选项来声明更大的流量控制窗口。
窗口比例因子(Window Scale Factor)为Kind=3的TCP选项,如下图所示。该选项用1字节的数据给出了窗口数值向左移位的量(因而该值又常称为移位计数(shift count)),即实际窗口的大小为“窗口”中的值乘以,其中f为窗口比例因子的数值。标准(RFC 1323)规定,f应取0~14之间的值,即窗口最大可达到字节。
注:RFC 1323规定,窗口比例因子选项须在TCP连接建立阶段声明,在通信阶段,TCP报文段中不允许出现该选项。即使出现,也将被忽略。
5.7.1 利用滑动窗口实现流量控制
教材在P227-228页用图5-22给出了以滑动窗口机制实现流量控制的示例,教材上讲得很清楚
注1:图5-22有一个前提,即在A端发送第一个报文段之前,B端告诉A端它的窗口值是400字节。
注2:TCP流控计算中的一个要点是:当发送方收到接收方报告的值为W确认号为ackx的窗口值时,一般情况下,发送方已经发送了序号ackx开始的y字节的数据,因而发送方还可以发送的就是ackx+y开始的W - y字节的数据。
零窗口死锁问题:假如TCP的接收端B收到的数据正好是其空余缓存的容量,这时,B就会发送一个确认报文段S1,该报文段中会声明窗口为0,即告诉发送端A没有接收空间了。A收到此报文段后,就不会再向B发送数据。此后如果B端的应用进程很快取完了接收缓存中的数据,则B端会向A端发送一个不携带数据的报文段S2,S2中报告窗口的大小为整个缓存的大小。假若S2在网络中丢失了,则由于B端缓存空了,它因接收不到A端的数据,就不会再发送报文到A以重复报告非零窗口,而A端得不到B端非空窗口的信息它也不会向B端发送数据,因而双方进入了一种死锁状态。
零窗口死锁问题的解决方法:零窗口探测报文。当A端收到B端的零窗口报文段后,就启动一个持续计时器(persistent timer),若该计时器时间到了,A端还没有收到B端的报文,则A端就发送一个零窗口探测报文,该报文只携带1字节的数据,这样B端收到此零窗口探测报文后,就会发回对该报文的确认。如果该确认中携带了非零窗口信息,则死锁解除;如果仍然是零窗口,则发送端再次设置持续计时器(persistent timer)。该过程会重复进行,直至死锁解除。
5.8 TCP的拥塞控制
网络拥塞(congestion)的定义:若在某段时间,网络的通信负荷使得对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫做网络拥塞,简称为拥塞。这里所说的资源指的是网络中的链路容量(即带宽)、交换结点中的缓存和处理机等等。
拥塞控制(congestion control)的定义:对网络拥塞采取措施以使其解除的策略或方法称为网络的拥塞控制。
5.8.1 拥塞控制的一般原理
路由器上的丢包是造成网络拥塞的主要原因之一:当路由器的某个出口缓存被多对通信竞争使用时,就可能造成出口缓存的溢出,从而导致丢包。而丢包会引起竞争此出口的发送端产生TCP报文段的超时重传,也就是引起网络拥塞。而超时重传会使发送到网络中的数据量多于实际要发送的数据,而多余的发送又会进一步加重网络拥塞,导致更多的超时重传。这样恶性循环,使得发送到网络中的数据变成了2倍或多倍于实际发送的数据量,最终使得网络的吞吐量严重地降低。极端情况下,网络吞吐量会变成0,即成为“死掉”的网络。因此对网络设计拥塞控制策略是确保网络可用性的必要任务之一。
拥塞控制必须是网络运行过程中自动执行的动作,因而它必定是一种闭环控制,也就是基于反馈的控制。具体地说,网络发生拥塞时,发送方能够通过某种迹象的反馈检测到拥塞,并据此降低数据发送速率,直至拥塞解除。而当没有拥塞时,就采取聪明的机制加大一些发送速率,以使网络的效率得到较好的发挥。
5.8.2 TCP的拥塞控制方法
教材在P232-236页用图5-24-27给出了TCP的拥塞控制的解释,教材上讲得很清楚,特别要注意对图5-25的学习和掌握,该图用一个拥控窗口随轮次的变化曲线说明了TCP拥塞控制的各个种情况和相应的策略。
TCP通过两个事件来检测网络的拥塞:
-
超时:当TCP发现某个报文段因为超时而要重传时,就会认为网络发生了拥塞。
-
三次重复的ACK:当TCP发现对某个数据序号出现了三次重复的ACK时,也会认为网络发生了拥塞。
TCP进行拥塞控制需要如下几个先决要素:
-
最大报文段长度MSS:TCP以MSS为单位开展拥塞控制。
-
拥塞控制窗口(congestion window, cwnd):TCP通信的每一端都设置拥塞控制窗口,实际上就是此前介绍可靠传输时的发送窗口。实际上,更一般的情况下,发送窗口是拥塞控制窗口和流量控制窗口中较小的那一个。尽管cwnd大小动态变化,但是依然是在发送缓存的范围内循环使用的。拥塞控制窗口的大小是以MSS为单位的。
-
发送轮次:TCP的拥塞控制以轮次为单位,一个轮次指的是将当前拥塞窗口中的报文全部以流水线方式连续地发送出去到收到其中最后一个报文的ACK的过程。该过程所用的总时间是RTT加上该轮次所有报文的发送时延。
-
慢启动门限(SSThresh, slow-start threshold):TCP拥塞控制中的第一个方法就是慢启动,慢启动需要一个门限值,称为慢启动门限,其单位也是MSS。慢启动过程中拥塞窗口会在一个轮次后加倍,但拥塞窗口大小达到慢启动门限时,慢启动过程就结束了。
TCP拥塞控制的要点:
-
慢启动(slow-start):
TCP连接建立后将拥塞窗口设为1个MSS。在第一个轮次中,将拥塞窗口中的数据(1个MSS长)用一个报文段发送出去;如果正常收到确认,则将拥塞窗口加倍,变成2个MSS长,并且构造两个报文段将窗口中的数据全部发送出去;依次进行下去,直到拥塞窗口达到SSThresh的大小。
下图给出了慢启动的示意。
下图给出了TCP拥控的各种情况和相应的策略示例。 -
拥塞避免(congesttion avoidance):
当拥塞窗口大小以慢启动达到SSThresh时,就进入拥塞避免阶段。在该阶段中也是每一个轮次都将拥塞窗口中的数据构造相应个数的TCP报文段,连续发送出去,但是如果正常收到确认,则仅将拥塞窗口增大1个MSS长度,即缓慢增加拥控窗口的大小。 -
发生三次重复的ACK事件:
将拥塞窗口减小到当前大小的,开始新一起点的拥塞避免过程。由于拥塞窗口减小为当前窗口的,使发送端发送到网络中的数据率明显减小,因而达到了拥控的目的。 -
快重传(fast retransmit):
为了对网络拥塞进行及时的反馈,TCP规定当接收端收到了一个失序的报文段时,就立即发送对连续收到报文段后的第一个字节号发送确认,这样可以使发送端能尽快地获知三次重复的ACK。当发送端收到三个重复的ACK时,就立即发送该ACK要求的报文段,此称为快重传。
注:快重传是与发生三次重复的ACK事件的动作结合进行的。 -
发生超时事件—快恢复(fast recovery):
将SSThresh设为当前拥塞窗口的,再将拥塞窗口大小设为1个MSS,进入慢启动过程。这一动作使得注入到网络中的数据量一下降低到最低限度,从而最快地解除拥塞,因而又称为快恢复。
注:之所也发生三次重复的ACK事件比发生超时事件采用了较为弱一些的拥控动作,是因为发生三次重复的ACK说明尽管网络发生了拥塞,但是ACK还可以传回来,而发生超时表明ACK都传不回来了。因而当发生超时事件时,需要立即将发送到网络的数据降到最低限度,以迅速解除拥塞,而当发生三次重复的ACK事件后,将拥控窗口减半的做法在缓解拥塞的同时还能保证较好的网络利用率。
拥塞控制与流量控制的不同
流量控制情况较为简单,它只发生在一对TCP通信的两个端点之间,通过让接收端报告其剩余的接收容量,使得发送端仅发送该容量范围内的数据,从而确保不要因发送端过快的数据发送造成接收端来不及接收。
拥塞控制则具有全局性。某个路由器出口缓存,或更广泛的网络资源,出现超负荷现象时,会导致通过该端口转发,或使用该网络资源,的所有竞争者都可能均出现拥塞事件(三次重复的ACK或超时),那么它们都会自动采取上述的拥控动作,从而共同缓解网络的拥塞。
TCP拥控设计的高明之处在于,尽管看起来并没有一个明显的全局拥控指令,但是仍然很好地实现了使拥塞各方降低注入到网络的数据率从而达致全局性拥控的效果。
5.9 TCP的运输连接管理
前已述及,TCP是一个面向连接的网络协议,而面向连接包括连接建立、通信和连接维护、连接释放3个阶段。前面我们对其中的通信阶段所涉及的方方面面进行了学习,本节将学习连接建立和连接释放这两个阶段的内容。
5.9.1 TCP的连接建立
TCP建立连接采用的是一种三次握手机制,如下图所示。
注:教材图5-28在左右两端均增加了状态描述
TCP三次握手建立连接的要领:
-
第1次握手:客户端构造一个SYN控制位置位的报文段,随机选取一个序号值x,并将该报文发送到服务器端。
-
SYN标志置位表示该报文是一个建立连接的报文。
-
该报文中不携带任何数据。
-
该报文的ACK标志位为0值,表示ack字段的值没有意义,一般取0。
注:TCP的所有报文中,只有这建立连接的第1次握手的报文ACK是不置位的,后面所有的报文ACK都会置位,如果没有接收到新的数据,则会发送重复的确认。 -
第2次握手:服务器收到客户端要求建立连接的报文后,构造一个SYN和ACK标志位均置位的报文,随机选取一个序号值y,确认号填入x+1,并发送到客户端。
-
尽管第1次握手的报文中不包含数据,但确认号规定取x+1,就好像是客户端发送了一个字节的数据。
-
y独立随机选取,与x在数值上没有任何关系。
-
该报文也不携带任何数据。
-
第3次握手:客户端收到服务器端发回的第2次握手的报文后,构造一个ACK置位的报文,其中的序号填入x+1,确认号填入y+1,并发送到服务器端。
-
第3次握手SYN标志位不再置位。
-
第3次握手可以不携带数据,也可以携带数据。
-
尽管第2次握手的报文中不包含数据,但确认号规定取y+1,就好像是服务器端发送了一个字节的数据。
因为这个三次握手 可能导致黑客利用syn进行攻击
服务器可以设置超时计时器
5.9.2 TCP的连接释放
TCP释放连接采用的是一种两阶段四次握手机制,如下图所示。
注1:教材图5-29在左右两端均增加了状态描述
注2:释放连接每个阶段的第一次握手报文均须是FIN控制位置位的报文。
这个seq是序号 前面已经传送过的数据的最后一个字节+1 那么v就是服务器的传送过的最后一个字节数据+1