当前位置:   article > 正文

《计算机网络--自顶向下方法》第三章--运输层_计算机网络:自顶向下方法 第三章fsm

计算机网络:自顶向下方法 第三章fsm

3.1概述和运输层服务  

运输层协议为运行再不同主机上的应用进程之间提供了逻辑通信(logic communication)功能

运输层协议是在端系统中而不是在路由器中实现的

3.1.1运输层和网络层的关系

运输层协议至工作在端系统中

在端系统中,运输层协议将来自应用进程的报文移动到网络边缘(即网络层),对有关这些报文在网络核心如何移动不作任何规定

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

3.1.2因特网运输层概述

因特网网络层协议中的IP(网际协议),为主机之间提供了逻辑通信。IP的服务模型是尽力而为交付服务(best-effort delivery service),不做任何保证,不确保报文段的交付,不保证报文段的按序交付,不保证报文段中数据的完整性。IP被称为不可靠服务(unreliable service)

UDP与TCP最基本的责任是:将两个端系统间IP的交付服务扩展为运行在端系统上的两个进程之间的交付服务。

将主机间交付扩展到进程间交付被称为运输层的多路复用(transport-layer multiplexing)多路分解(demultiplexing)

进程到进程的数据交付和差错检查是两种最低限度的运输层服务,也是UDP所能提供的仅有的两种服务。TCP提供可靠数据运输和拥塞控制

3.2多路复用和多路分解

一个进程(作为网络应用的一部分)有一个或多个套接字,它相当于从网络向进程传递数据和从进程向网络传递数据门户。

将运输层报文段中的数据交付到正确的套接字的工作称为多路分解(demultiplexing)

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

运输层多路复用要求:①套接字有唯一标识符②每个报文段有特殊字段来只是该报文段所要交付到的套接字

运输层分解服务:在主机上的每个套接字能够分配一个端口号,当报文段到达主机时,运输层检查报文段中的目的端口号,并将其定向到相应的套接字

1.无连接的多路复用与多路分解

运输层将得到的报文段传递到网络层

网络层将该报文段封装到一个IP数据报中,并尽力而为的将报文段交付给接收主机

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

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

TCP套接字是由一个四元组(源IP地址,源端口号,目的IP地址,目的端口号)标识。

两个具有不同源IP地址或源端口号的到达TCP报文段将被定向到两个不同的套接字

即使两个套接字有相同的端口号,服务器仍然能正确的分解两个具有相同源端口号的连接,因为这两天连接有不同的源IP地址

3.web服务器与TCP

服务器为每条连接生成一个新进程,每个这样的进程都有自己的连接套接字,通过这些套接字可以收到HTTP请求和发送HTTP响应

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

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

3.3无连接运输:UDP

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

采用UDP的原因:

①关于发送什么数据以及何时发送的应用层控制更为精细。TCP的拥具有拥塞控制机制,它保证报文的可靠交付,却不管可靠交付需要多少时间。实时应用通常要求最小的发送速率,不希望过分的延迟报文段的传送,且能容忍一些数据丢失。

②无需连接建立。UDP不需要任何准备即可进行数据传输。

③无连接状态。TCP需要在端系统中维护连接状态,包括接收和发送缓存、拥塞控制参数以及序号与确认号的参数。UDP不维护连接状态,也不追踪这些参数 

④分组首部开销小。每个TCP报文段都有20字节的首部开销,而UDP仅有8字节的开销

 

UDP中缺乏拥塞控制可能导致UDP发送方和接收方之间的高丢包率,并挤垮TCP绘画,这是一个潜在的严重问题

价格可靠性直接构建于应用程序中可以使其适应更多环境,也就是说应用进程可以进行可靠通信而无需受制于由TCP拥塞控制机制强加的传输速率限制

3.3.1UDP报文段结构

 应用层数据占用UDP报文段的数据字段

UDP首部只有四个字段,每个字段由两个字节组成。通过端口号可以使目的主机讲应用数据交给运行在目的端系统中的相应进程(即执行分解功能)。长度字段只是了在UDP报文段中的字节数(首部+数据)接收方使用检验和来检查在该报文段中是否出现了差错

3.3.2UDP检验和

UDP检验和提供了差错检查功能。检验和用于确定当UDP报文段从源到达目的地移动时,其中的比特是否发生了改变(由于链路中的噪声干扰或者存储在路由器中时引入问题)

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

由于不能保证源和目的之间的所有链路都提供差错检测,也无法确保内存中的差错检测的情况下,如果端到端数据传输服务需要差错检测,那么UDP就必须在端到端的基础上再运输层提供差错检测。

UDP提供的检验和,只用于检验是否该报文有改变,不提供差错恢复功能。

3.4可靠数据传输原理

可靠数据传输协议(reliable data transfer protocol)为上层实体提供的服务抽象是:数据可以通过一条可靠的信道进行传输。借助于可靠信道,传输数据比特就不会收到损坏或丢失,而且所有数据都是按照其发送顺序进行交付

分组将以他们发送的次序进行交付,某些分组可能会丢失,但是底层信道不会对分组重新排序

仅考虑单向数据传输(unidirectional data transfer),即数据传输是从发送端到接收端的

3.4.1构造可靠数据传输协议

发送方和接收方的有限状态机(Finite-State Machine,FSM),FSM定义了发送方和接收方的操作,FSM描述图中的箭头指示了协议从一个状态变迁到另一个状态。引起变迁的时间显示在标识变迁的横线上方,事件发生时所采取的动作显示在横线下方。使用符号^,标识缺少动作或事件

FSM初始状态用虚线标识

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

rdt1.0发送端:只通过rdt_send(data)事件接收来自较高层的数据,通过packet=make_pkt(data)产生一个包含该数据的分组,并将分组发送到信道中。

rdt2.0接收端:通过rdt_rcv(packet)事件从底层信道接收一个分组,通过extract(packet,data)从分组中取出数据,并通过deliver_data(data)将数据上传给较高层。

在这个简单协议中,一个单元数据与一个分组没有差别,所有分组是从发送方流向接收方。

有了完全可靠的信道,接收端就不需要提供任何反馈信息给发送方

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

在分组的传输、传播或缓存的过程中,比特差错通常会出现在网络的物理部件中

肯定确定(positive ackonwledgment)否定确定(negative acknowledgment)两种控制报文可以使得接收方让发送方知道那些内容被正确接收,那些内容接收有误需要重复。基于这样重传机制的可靠数据传输协议称为自动重传请求(AUtomatic Repeat reQuest,ARQ)协议

ARQ用于处理比特差错需要的三种协议功能:

·差错检测:使接收方检测到何时出现了比特差错。比如UDP报文段中的检验和字段。

·接收方反馈:发送方了解接收方的情况需要接收方提供明确的反馈信息。比如肯定确定和否定确定两种机制

·重传:接收方收到有差错的分组时,发送方将重传该分组

 rdt2.0发送端:

①最左边状态:发送端协议等待来自上层传下来的数据,出现rdt_send(data)事件时,发送方将产生一个包含待发送数据的分组sndpkt,带有检验和,通过udt_send(sndpkt)操作发送该分组

②最右边状态:发送方协议等待来自接收方的肯定确定或者否定确定分组。如果收到一个肯定分组,则发送方知道最近发送的分组被正确接收rdt_rcv (rcvpkt)&&isACK (rcvpkt)。如果收到一个否定分组,该协议重传上一个分组并等待接收方为响应重传分组而回送的肯定分组和否定分组。

当发送方处于等待肯定确定或否定确定分组的状态时,它不能从上层获得更多的数据。也就是发送方将不会发送一块新数据,除非发送发确定接收方已经正确接收分组。因此rdt2.0这种协议也叫停等(stop-and-wait)协议

rdt2.0接收端:当分组到达时,接收方要么回复肯定确定,要么回复否定确定。rdt_rcv (rcvpkt) &¬corrupt(rcvpkt)对应于收到一个分组并发现有错的事件

后面用ACK描述肯定确定,NAK描述否定确定,事实上ACK与NAK也有分组受损的可能性

ACK和NAK受损的三种可能性:
·报文混淆:判断ACK与NAK时,可能会导致接收方无法理解新的ACK或NAK是新报文,还是重传的内容

·增加足够的检验和比特:使发送方不仅可以检测差错,还可恢复差错。对于产生差错但不丢失分组的信道,可以直接解决问题

·出现受损直接重传:在发送方到接收方的信道中引入了冗余分组(duplicate packet)。冗余分组根本困难在于接收方不知道上次所发送的ACK和NAK是否被发送方正确接收

解决办法:
在数据分组中添加一个新的字段,让发送方对其数据分组编号,即将发送数据分组的序号(sequence number)放在该字段。接收方检查序号即可确定收到的分组是否是一次重传。

 rdt2.1发送方和接收方的FSM状态数都是以前的两倍,因为协议状态此时必须反映出目前正发送的分组或接收方希望接收的分组的序号是0还是1。当接收到失序的分组时,接收方对所接受的分组发送一个肯定确认。如果收到受损的分组,则接收方将发送一个否定确认。

如果不发送NAK,而是对上一次正确接受的分组发送一个ACK,也可以实现一样的效果。发送方接收到同一个分组的两个ACK之后,就知道接收方没有正确的接收到被两次确认后发送的分组。

 rdt2.2是在具有比特差错信道上实现的一个无NAK的可靠数据传输协议

rdt2.1和rdt2.2的区别在于,接收方此时必须包括由一个ACK报文确认的分组序号(通过接收方FSM中make_pkt()中包括参数ACK 0和 ACK 1来实现),发送发此时必须检查接收到的ACK报文中被确认的分组序号(通过发送方FSM中isACK()中包括参数 0 或 1 来实现)

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

现在除了比特受损外,底层信道还会丢包。协议的关键问题在于怎样检测丢包以及发生丢包后如何处理

如果分组丢失或者该分组的ACK丢失,发送方都接收不到来自接收方的响应,那么只要发送方等待足够的时间就可以确定分组丢失。最短时间=发送方与接收方之间的往返时延+接收方处理分组时间。

但是由于最坏情况下的最大时延很难估算,所以采取发送方选择一个确定的时间值,不论接收方是否接收到报文,只要超过该时间发送方没有接收来自接收方的响应就重发。也就是如果一个分组经历了一个特别大的时延,发送方有可能会重传该分组,即使该数据分组及其ACK都没有丢失。这就在发送方到接收方的信道中引入了冗余数据分组(duplicate data packet),在前面rdt2.2中通过序号就实现了处理冗余分组情况

对于发送方来讲,报文发生问题,只需要重传该报文就可以解决。所以引入倒计数定时器,实现基于时间的重传机制,在一个给定的时间量过期后,中断发送方。发送方需要:①每次发送一个分组时,就启动一个定时器②响应定时器中断③终止定时器

 下图显示在有丢包和延迟分组下协议运作的情况,以及它是如何处理数据分组丢失的

 一个分组的接收时间必定是迟于一个分组的发送时间,这是由于发送时延和传播时延

因为分组序号在0和1之间交替,所以rdt3.0有时被称为比特交替协议(alternating-bit protocol)

综上所述,实现可靠数据传输协议需要检验和、序号、定时器、肯定确认和否定确定机制

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

出现流水线可靠数据传输协议的原因,是因为rdt3.0作为一个停等协议,存在性能问题

用一种理想化的情景计算停等协议利用率:

假设两个端系统之间往返传播时延RTT大约30毫秒,通过一条发送速率R为1Gbps的信道连接,一个包括首部字段和数据的分组L长为1000字节

发送一个分组进入链路需要的时间为:t=L/R=8000bit/pkt / 10^9 bit/s = 8 μs/pkt

接收方接收到全部分组的时间为:t=RTT/2 + L/R = 15.008 ms

接收方接收全部分组后立刻发送ACK,发送方接收到ACK时间为:15 + 15.008 = 30.008ms

从上面的计算可以看出,发送方在30.008ms的时间内,发送只用了0.008ms,发送方的利用率=0.008/30.008=0.00027,在链路发送速率为1Gbps并且不考虑其他时延的前提下利用率都如此低,采用停等协议的传输成本太高。

 因此采用不停等的方式运行,运行发送方发送多个分组而无需等待确认。发送方在等待确认之前发送N个报文,其利用率也提高N倍,这种方式被称为流水线

采用流水线带来的影响:

①必须增加序号范围。每个输送中的分组必须有一个唯一的序号,而且也许有多个在输送中尚未确认的报文

②协议发送方和接收方需要缓存多个分组。发送方最低限度应当能缓冲那些已经发送但是还没有确认的分组

③所需序号范围与缓冲要求取决于数据传输协议如何处理丢失、损坏以及延时过大的分组。解决流水线差错恢复的两种基本方法:回退N步 选择重传

3.4.3回退N步

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

 如上图所示

基序号为最早未确认分组的序号,下一个序号为最小的未使用序号(即下一个待发分组的序号)。大于或等于base+N的序号是不能使用的,直到当前流水线中未被确认的分组被确认为止。

已经被发送但是还未被确认的分组的许可序号范围可以视为一个在序号范围内长度为N的窗口,随着协议的运行,该窗口在序号空间内向前滑动。N也被称为窗口长度(window size),GBN协议也常被称为滑动窗口协议(sliding-window protocol)。设置N而不是无限制发送分组,是由于流量控制对发送方的限制

一个分组的序号承载在分组首部的一个固定长度的字段中。如果分组序号字段的比特数是k,那么序号范围为【0,2^k - 1】。在一个有限的序号范围内,所有设计序号的运算必须模2^k(可以理解为序号范围是一个环,当序号使用到2^k - 1之后,将会从0重新开始)

 上图是基于ACK、无NAK的GBN协议的发送方和接收方两端的扩展FSM描述

GBN发送方必须响应的三种类型事件:
·上层的调用:当上层调用rdt_send()时,发送方首先检查发送窗口是否已满(即是否有N歌已发送但未被确认的分组)。如果窗口未满,则产生一个分组将其发送并相应的更新变量;如果窗口已满,发送方只需要将数据返回给上层,隐式的指示上层该窗口已满。发送方一般会缓存这些数据而不是立刻发送,或者使用同步机制使得上层只能在窗口不满时调用rdt_send()

·收到一个ACK:在GBN协议中,对序号为n的分组的确认采取累积确认(cumulative acknoledgment)的方式,表明接收方已经正确接收到序号为n的以前且包括n在内的所有分组

·超时事件:定时器将再次用于恢复数据或者确认分组丢失,如果出现超时,发送方重传所有已经发送但还没被确认的分组。如果收到一个ACK,但是仍有已经发送还未被确认的分组,则定时器被重新启动。如果没有已经发送还未被确认的分组,停止定时器。

GBN中接收方动作:
·正确接收:如果一个序号为n的分组被正确接收到,并且按序,则接收方为分组n发送一个ACK,并将该分组中的数据部分交付给上层

·在所有其他情况下:接收方丢弃该分组,并为最近按序接收的分组重新发送ACK,这样发送方就能知道分组丢失。

由于一次向上层交付一个分组,如果分组k被接收方接收,并且被交付给上层,那么前k-1个分组一定都已经交付

数据必须要按序交付给上层,所以接收方会丢失所有失序分组,这种方法接收缓存简单,接收方不需要缓存任何失序分组

 如上图所示,接收方分组2丢失,分组3、4、5被发现是失序分组并被丢弃

3.4.4选择重传

GBN协议允许发送发用多个分组“填充流水线”,因此避免了停等协议带来的信道利用率低问题。当窗口长度和带宽时延都很大时,单个分组的差错导致GBN大量重传分组,可能导致信道被不必要重传的分组占据。

选择重传(SR)协议通过让发送方仅重传那些他怀疑在接收方出错的分组,从而避免了不必要的重传

这种个别的,按需的重传要求接收方逐个的确认正确接收的分组,通过窗口长度N来限制流水线中未完成,未被确认的分组数

 

SR接收方将确认一个正确接受的分组不论它是否有序。失序的分组会被缓存,直到所有丢失分组都被收到为止,此后将这一批分组按序交付给上一层

如果分组send_base的ACK没有从接收方传播回发送方,则发送方最终会重传send_base分组。如果接收方不确认该分组,则发送方窗口将永远不会向前滑动。

SR发送方的事件与动作:

1.从上层收到数据:当从上层接收到数据后,SR发送方检查下一个可用于该分组的序号。如果序号位于发送方的窗口内,则将数据打包发送;否则与GBN类似,要么将数据缓存,要么将数据返回上层以便之后传输

2.超时:定时器用来防止丢失分组,每个分组拥有自己的逻辑定时器从而实现超时之后能只重复丢失分组。可以使用单个硬件定时器模拟多个逻辑定时器的操作

3.收到ACK:收到ACK,如果该分组序号在窗口内,则SR发送方将被确认的分组标记为已经接收;如果该分组序号等于send_base,则窗口基序号向前移动到最小序号未确认分组处;如果窗口移动了并且接受序号在窗口内未发送的分组,则发送这些分组至上一层

SR接收方的事件与动作:

1.序号在[rcv_base,rce_base+N-1]内的分组被正确接收:收到的分组在接收方的窗口内,一个选择ACK发送回发送方。如果该分组以前没有收到过,则缓存该分组;如果分组序号等于接收窗口的基序号(rcv_base),则该分组以及以前缓存的序号连续的分组交付给上层。接收窗口按照向前移动分组的编号向上交付这些分组

2.序号在[rcv_base-N,rcv_base-1]内的分组被正确收到:必须产生一个ACK,即使该分组是接收方以前已经确认过的分组

3.其他情况:忽略该分组

从上图可以看出,对于那些分组已经被正确接收,那些没有,发送方和接收方并不总是能看到相同的结果,也就是说发送方和接收方的窗口并不总是一致。

当面对有限序号范围时,发送方和接收方窗口缺乏同步带来的后果

如下图所示,包括4个分组序号0、1、2、3的有限序号范围,且窗口长度为3。假定发送了分组0--2,并接收方正确接收且确认了,接受方窗口此时在4、5、6上,序号分别为3、0、1

情形一:对前三个分组的ACK丢失,发送方重传这些分组,接收方下一步要接收序号为0的分组,即第一次发送分组的副本

情形二:前三个分组的ACK都被正确交付给发送方。发送方向前移动窗口并发送第4、5、6个分组,序号分别为3、0、1。序号为3的分组丢失,但是序号为0的分组到达

上面的两种情形对于接收方来说,实际上是等同的,接收方没有办法区分是第一个分组的重传还是第五个分组的初次传输,当窗口长度比序号空间小1时协议无法工作

 因此,窗口长度必须小于等于序号空间大小的一半

可靠数据传输机制及其用途的总结
机制用途和说明
检验和用于检验一个在传输分组中的比特错误
定时器

用于超时/重传一个分组,可能因为该分组(或ACK)在信道中丢失了。

由于当一个分组延时但未丢失,或当一个分组已被接收方接收到但从接收方发向发送方的ACK丢失时,可能产生超时事件,所以接收方可能会收到一个分组的多个冗余副本

序号

为从发送方流向接收方的数据分组按顺序编号。

所接收分组的序号间的间隙可使接收方检测出丢失的分组。具有相同序号的分组可使接收方检测出一个分组的冗余副本

确认(ACK)

接收方用于告诉发送方一个分组或者一组分组已经被正确的接收到。

确认报文通常携带着被确认的分组或多个分组的序号。确认可以是逐个的或者累计的

否定确认(NAK)

接收方用于告诉发送方一个分组未被正确接收。

否定报文通常携带着未被正确接收的分组的序号。

窗口、流水线

发送方也许被限制仅发送那些序号在一个指定范围内的分组。通过允许一次发送多个分组但未被确认,发送方的利用率可在停等操作模式的基础上得到增加。

窗口长度可以根据接收方接收和缓存报文的能力,网络中的拥塞程度或两者情况来设置。

3.5面向连接的运输:TCP

3.5.1TCP连接

TCP连接不同于电路交换网络中端到端的TDM或FDM电路,而是一种逻辑连接。TCP协议旨在端系统中运行,不会在中间的路由器或者链路层交换机中运行,所以中间的网络元素不会维持TCP连接状态。

TCP连接提供的是全双工服务(full-duplex service):如果一台主机上的进程A与另一台主机上的进程B存在一条TCP连接,那么应用层数据就可以在从进程B流向进程A的同时,也从进程A流向进程B

TCP连接是点对点(point-to-point)的:即TCP是单个发送方与单个接收方之间的连接

TCP连接建立方式:客户首先发送一个特殊的TCP报文段,服务器用另一个特殊的TCP报文来响应,最后客户再用第三个特殊报文段作为响应。前两个报文段不承载“有效载荷”,也就是不包含应用层数据,而第三个报文段可以承载有效载荷。由于在这着两个主机之间发送了3个报文段,所以这种连接过程称为三次握手

客户进程通过套接字传递数据流,数据一旦通过该套接字就有客户中运行的TCP控制。TCP将这些数据引导到该连接的发送缓存(send buffer)中,发送缓存时发起三次握手期间设置的缓存之一。

TCP可从缓存中取出并放入报文段的数据数量受限于最大报文段长度(Maximum Segment Size,MSS)。MSS通常更具最初确定的有本地发送主机发送的最大链路层帧长度(即最大传输单元(Maximum Transmission Unit,MTU))来设置。

MTU=MSS+TCP/IP首部长度(通常为40字节)

TCP为每块用户数据配上一个TCP首部,从而形成多个TCP报文段 。这些报文段被下穿给网络层,网络层将其分别封装在网络层IP数据报中。然后子啊写IP数据报被发送到网络中》当TCP在另一端接收到一个报文段后,该报文段的数据就被放入该TCP连接的接受缓存中。应用程序从该缓存中读取数据流。

3.5.2TCP报文段结构

 TCP发送一个大文件时,TCP通常是将文件划分为长度为MSS的若干块,最后一块的长度通常小于MSS。

然而,对于交互式应用通常传输长度小于MSS的数据块。例如:对于Telnet这样的远程登陆应用,其TCP报文段的数据字段通常只有一个字节,TCP报文段的首部一般是20字节,所以有时候Telnet发送的报文段允许只有21字节长。

TCP报文段结构与UDP一样,首部包括源端口号目的端口号,被用于多路复用/分解来自或送到上层应用的数据,TCP首部也包括检验和字段

TCP报文段首部:

①32比特的序号字段sequence number field)和32比特的确认号字段(acknowledgment number field):这些字段被TCP发送方和接收方用来实现可靠数据传输服务

②16比特的接收窗口字段(receive window field):该字段用于流量控制,指示接收方愿意接受的字节数量

③4比特的首部长度字段(header length field):该字段只是了以32比特的字为单位的TCP首部的长度,由于TCP选项字段的原因,TCP首部的长度是可变的。(通常,选项字段为空,TCP首部的典型长度是20字节)

④可选与变长的选项字段(options field):该字段用于发送方与接收方协商最大报文段长度(MSS)时,或在告诉网路环境下用作窗口调节因子时使用。首部字段中还定义了一个时间戳选项。详见RFC 854RFC 1323

⑤6比特的标志字段(flag field)ACK比特用于指示确认字段中的值时有效的,即该报文段包括一个对已经被成功接受报文段的确认。RST、SYNFIN比特用于连接建立和拆除。CWRECE比特用于明确拥塞通告。当PSH比特被置位时,就指示接收方应该立即将数据交给上层。URG比特用来指示报文段里存在着被发送端的上层实体标记为“紧急”的数据。紧急数据的最后一个字节由16比特的紧急数据指针字段指出。当紧急数据存在并给出指向紧急数据尾指针的时候,TCP必须通知接收端的上层实体。(在实际中,PSH、URG和紧急数据指针并没有使用)

1.序号和确认号

TCP报文段首部中最重要的两个字段是序号字段和确认号字段

TCP把数据堪称一个无结构的、有序的字节流。因为序号是建立在传送的字节流之上,而不是建立在传送的报文段的序列之上,一个报文段的序号是该报文段首字节的字节流编号。TCP隐式的对数据流中的每个字节编号。

如下图所示,MSS为1000,给第一个报文段分配序号为0,第二个报文段分配序号为1000,第三个报文段分配序号为2000,以此类推。每一个序号都被填入相应的TCP报文段首部的序号字段中。

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

TCP提供累计确认:无论丢失了多少接收方返回的确认,对于发送发方来说,只要是在发送方超时时间之内成功接到了接收方返回的一串应答中的最后一个,则包含了前面全部的确认信息。累积确认的目的是为了避免一系列应答中的某个应答丢失造成的无必要的重传

当主机在一条TCP连接中收到失序报文段时:①接收方立即丢失失序报文段②接收方保留失序的字节,并等待缺少的字节以填补该间隔

2.telnet:序号和确认号的一个学习案例

 Telnet是一个用于远程登陆的流行应用层协议。

假设主机A发起一个与主机B的Telnet会话,主机A为客户,主机B为服务器。客户端的用户键入的每个字符都会被发送到远程主机,远程主机将回送每个字符的副本给客户,并将这些字符显示在Telnet用户的屏幕上。这种回显用于确保由Telnet用户发送的字符已经被远程主机接收到并且在远程站点上得到处理。因此,在从用户键入到字符回显的时间内,每个字符在网络中传输了两次。

假设用户和服务器的起始序号分别是42和79,在TCP连接建立后但没有发送任何数据之前,该客户等待字节79,而服务器等待字节42.

如上图所示,第一个报文段是由客户发往服务器的,报文段的序号字段里是42,确认号字段中是79;

第二个报文段是由服务器发往用户的,通过在确认号字段中填入43告诉用户服务器以及成功接受到字节42及以前的所有字节,目前等待字节43。并且回显字符。对客户到服务器的数据的确认被装载在一个服务器到客户的报文段中,这种确认被认为是被捎带在服务器到客户的数据报文段中的

第三个报文段是从客户发往服务器的,唯一的目的是确认已经从服务器收到数据。这个报文段里没有数据但仍然有确认号80,这是因为TCP存在v信号字段,报文段中需要填入一个序号。

3.5.3往返时间的估计与超时

TCP采用超时/重传机制来处理报文段丢失的问题

1.估计往返时间

RTT(Round Trip Time):一个连接的往返时间,即数据发送时刻到接收到确认的时刻的差值;

大多数的TCP实现仅仅在某一时刻为一个已发送但尚未确认的报文段做一次RTT采样,得到一个SampleRTT,而不是为每一个发送的报文段都测量RTT,从而用这个SampleRTT来接近(代表)所有RTT。

TCP不会为重传的报文段计算SampleRTT,只为传输一次的报文段测量SampleRTT。重传可能是偶发的网络抖动导致的,不足以放到整体样本

由于路由器的拥塞和端系统负载的变化,报文段的SampleRTT值会随之波动。所以采用加权平均计算一个合适的RTT值:

EstimatedRTT = (1 - α) * EsimatedRTT + α * SampleRTT

RFC 6298中 α = 0.125

EstimatedRTT = 0.875* EsimatedRTT + 0.125 * SampleRTT

这个加权平均对最近样本赋予的权值要大于对旧样本赋予的权值,这种平均被称为指数加权移动平均

α=1/8时,SampleRTT与EstimatedRTT的计算

除了估算RTT外,还需要测量RTT的变化,用于估算SampleRTT偏离EstimatedRTT的程度:

DevRTT = (1 - β) * DevRTT + β * |SampleRTT - EstimatedRTT|

β=0.25        SampleRTT值波动越小,DevRTT越小

2.设置和管理重传超时间隔

在测算出EstimatedRTT和DevRTT值之后,可以推算出TCP超时间隔,并且这个超时间隔大于等于EstimatedRTT,否则会导致不必要的重传。同时超时间隔不能大于EstimatedRTT太多,否则报文段丢失时,TCP不能很快重传,导致数据传输时延大

TimeoutInterval = EstimatedRTT + 4 * DevRTT

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

3.5.4可靠数据传输

因特网的网络层服务(IP服务)是不可靠的。IP不保证数据报的交付,不保证数据报的按序交付,也不保证数据报中数据的完整性。由于运输层报文段是被IP数据报携带者在网络中传输的,所以运输层的报文段也会遇到这些问题。

TCP在IP的不可靠尽力而为服务上创建了一种可靠数据传输服务。TCP的可靠数据传输服务确保一个进程从其接受缓存中读出的数据流是无损坏、无间隙、非冗余和按序的数据流。

理论上,对于每一个已经发送但是还未被确认的报文段都有一个定时器相关联,但实际上这种做法会造成较大的资源开销。因此实际场景下仅使用单一的重传定时器,即使有多个已经发送但是还未被确认的报文段

  1. //假设发送方不受TCP流量和拥塞控制的限制,来自上层数据的长度小于MSS
  2. //且数据传送只在一个方向进行
  3. NextSeqNum = InitialSepNumber;
  4. SendBase = InitialSepNumber;
  5. while(1)
  6. {
  7. switch 事件:
  8. {
  9. case 从应用程序接收到数据:
  10. 生成具有序号 NextSeqNum 的 TCP 报文段;
  11. if(定时器当前没有运行)
  12. 启动定时器;
  13. 向 IP 协议传递报文段;
  14. NextSeqNum = NextSeqNum + length(data); //更新序列号
  15. break;
  16. case 定时器超时:
  17. 重传具有最小序号但仍未应答的报文段;
  18. 重启定时器;
  19. break;
  20. case 收到 ACK,ACK 字段值为 y:
  21. if(y > SendBase)
  22. {
  23. SendBase = y;
  24. if(当前仍无任何应答报文段)
  25. 启动定时器;
  26. }
  27. break;
  28. }
  29. }

如上伪代码所示,有三个主要事件:从上层应用程序接受数据;定时器超时;收到ACK

第一个事件:TCP从引用程序接受数据,将数据封装在一个报文段中,并将该报文段转发给IP,当报文段被传给IP时,TCP就启动定时器(定时器与最早的未被确认的报文段相关联),该定时器的过期间隔是TimeoutInterval

第二个事件:TCP通过重传引起超时的报文段来响应超时事件,然后TCP重启计时器。

第三个事件:收到一个来自接收方的确认报字段(ACK)。TCP将ACK的值γ与SendBase进行比较。TCP状态变量SendBase是最早未被确认的字节的序号(SendBase-1=接收方已经正确按序接受到的数据的最后一个字节的序号)。由于TCP采用累计确认,所以γ确认了字节编号在γ之前的所有字节都已经收到

1.部分情况分析

第一种情况

(图3-34)

第二种情况

(图3-35)

第三种情况

(图3-36)

主机A向主机B发送一个报文段。

假设该报文段的序号是92,而且包含8字节数据。

在该报文段发出后,主机A等待一个来自主机B确认号为100的报文段。

虽然A发出的被B接收到了,但是B发出的确认报文丢失了。此时超时事件发生,主机A重传相同的报文段,也就是序号为92的报文段。当主机B收到该重传的报文段时,通过序号发现该报文段已经收到过,将会丢弃该重传的报文段。

主机A连续发送了两个报文段。

第一个报文段序号是92,包含8字节数据;第二个报文段序号是100,包含20字节数据。

假设两个报文段都完好无损地到达主机B;并且主机B为每一个报文段分别发送一个确认。第一个确认报文的确认号是100,第二个确认报文的确认号是20。

假设在超时之前这两个报文段没有一个确认报文达到主机A。

当超时事件发生时,主机A重传序号92的第一个报文段,并重启定时器。只要第二个报文段的ACK在新的超时发生之前抵达,则第二个报文段将不会被重传。

主机A连续发送了两个报文段。

第一个报文段的确认报文在网络中丢失,但在超时事件发生之前主机A收到一个确认号为120的确认报文段。主机A因此得知主机B已经获得了序号为119及之前的所有字节。

因此主机A不会重传报文段。

2.超时间隔加倍

TCP重传具有最小序号的还未被确认的报文段。每次TCP重传时都会将下一次的超时间隔设为先前值的两倍。

因此超时间隔在每次重传后会呈指数型增长。然而,每当定时器在收到上层应用数据或收到ACK时,TimeoutInterval由最近的EstimatedRTT值与DevRTT值推算得到。 

原因:

这种修改提供了一个形式受限的拥塞控制。定时器过期很可能是由网络拥塞引起的,即太多分组到达源于目的地之间路径上的一台(或多台)路由器的队列中,造成分组丢失或者长时间的排队时延。在本就拥塞的情况下,如果源持续重传分组会导致拥塞更加严重。所以TCP每个发送方的重传都经过越来越长的时间间隔。

3.快速重传

超时重传带来的问题

  • 当一个报文段丢失时,会等待一定的超时周期然后才重传分组,增加了端到端的时延。
  • 当一个报文段丢失时,在其等待超时的过程中,可能会出现这种情况:其后的报文段已经被接收端接收但却迟迟得不到确认,发送端会认为也丢失了,从而引起不必要的重传,既浪费资源也浪费时间。

发送方通过在超时事件发生之前通过冗余ACK来检测丢包情况。冗余ACK就是再次确认某个报文段的ACK,而发送方之前已经收到该报文段的确认报文。

如果接收方收到一个序号大于期望序号的报文段,也就是说由报文段缺失或者失序,此时它将对最后一个确认收到的有序报文段重新确认。每当比期望序号大的失序报文段到达时,发送一个冗余ACK,指明下一个期待字节的序号。

事件TCP接收方动作
具有期望序号的按序报文段到达。期望序号及其之前的报文段都已经被确认延迟的ACK。等待下一个有序报文段,对下一个按序报文段最多等待500ms。如果下一个按序报文段没有在这个时间间隔内到达,则发送一个ACk
具有期望序号的按序报文段到达。另一个按序报文段等待ACK传输立即发送单个累积ACK。确认收到期望序号报文段,同时请求下一个按序报文段
大于期望序号的失序报文段到达。检测出间隔立即发送冗余ACK,指示下一个期待序号报文段
能部分或者完全填充接受数据间隔的报文段到达如果该报文段起始于间隔的低端(也就是该报文段的序号=接收方期望序号),则立即发送ACK

由于发送方会持续发送大量报文段,如果一个报文段丢失,会导致多个冗余ACK。所以设定当TCP发送方接收到对相同数据的3个冗余ACK,则该被确认过3次的报文段之后的报文段丢失。

一旦收到3个冗余ACK,TCP就执行快速重传,即在该报文段定时器过期之前就重传丢失的报文段。

为什么是3个冗余ACK?

即使发送端是按序发送,由于TCP包是封装在IP包内,IP包在传输时乱序,意味着TCP包到达接收端也是乱序的,乱序的话也会造成接收端发送冗余ACK。那发送冗余ACK是由于乱序造成的还是包丢失造成的,并不确定。

乱序情况下:40%的概率收到3个冗余ACK

丢失情况下:100%的概率收到3个冗余ACK

基于以上的统计,当A接收到3次冗余ACK启动快速重传是合理的,即立马重传丢失报文段,可以起到快速覆盖的功效,快速修复一个丢包对TCP管道的恶劣影响。
而如果A接收到2次冗余ACK,则一定说明是乱序造成的,即然是乱序,说明数据都到达了B,B的TCP负责重新排序而已,没有必要A再来启动快速重传算法。

  1. //事件:收到ACK,具有ACK字段值y
  2. if(y>SendBase)
  3. {
  4. SendBase=y
  5. if(当前仍无任何应答报文段)
  6. {
  7. 启动定时器
  8. }
  9. }
  10. else//对已经确认的报文段的一个冗余ACK
  11. }
  12. 对y收到的冗余ACK数加1
  13. if(对y==3收到的冗余ACK数)
  14. {
  15. //TCP快速重传
  16. 新发送具有序号y的报文段
  17. }
  18. }
  19. break;

4.回退N步与选择重传

 TCP具有累计确认的特点,正确接受但是失序的报文段是不会被接收方逐个确认的。这个特点比较类似回退N步。但是TCP会将正确接受但是失序的报文段缓存,这种特点类似选择重传。

因此TCP是两者兼有的选择确认,它允许TCP接收方由选择的确认失序报文段,而不是累计的确认最后一个正确接受的有序段。将该机制于选择重传机制结合起来使用。

3.5.5流量控制

一条TCP连接的每一侧主机都为该连接设置了接收缓存。当该TCP连接接收到正确的、有序的报文段,就会将数据放入接收缓存。相关联的应用会从缓存中读取数据。

但是如果应用程序读取数据的速度相对较慢,而发送方发送的太多、太快,会导致缓冲区溢出。

TCP为应用程序提供流量控制服务(flow-control service),从而减少接收方缓存溢出的情况。流量控制就是使发送速率与接受速率相匹配。

如果发送方因为IP网络的拥塞被制约,那么这种流量控制被称为拥塞控制(congestion control)

TCP通过让发送方维护一个接收窗口(receive window)来提供流量控制。这个接收窗口用于指示发送方对应的接收方还有多少可用缓存空间。由于TCP是双全工通信,在连接两端的发送方都各自维护一个接收窗口

 假设主机A通过TCP向主机B发送一个文件。主机B为该连接分配一个接收缓存,用RcvBuffer来表示大小。

定义以下变量:

·LastByteRead:主机B上的应用进程从缓存中读取的数据流的最后一个字节的编号

·LastByteRevd:从网络中到达并且放入主机B接收缓存中的数据流的最后一个字节的编号

TCP不允许已经分配的缓存溢出,因此:

LastByteRcvd - LastByteRead ≤ RCVBuffer

接收窗口用rwnd表示,rwnd = RcvBuffer - [ lastByteRcvd - LastByteRead ],由于空间是随着时间变化的,所以rwnd是动态的

主机B将rwnd值放入它发给主机A的报文段接收窗口中,通知主机A它还有多少缓存空间可用。开始时,主机B设置rwnd = RcvBuffer

主机A轮流跟踪LastByteSent和LastByteAcked两个变量,这两个变量的差LastByteSent - LastByteAcked,就是主机A发送到连接中但还尚未被确认的数据量。

 因此主机A在连接销毁之前必须保证:

LastByteSent - LastByteAcked ≤ rwnd

问题:假设主机B的接收缓存已经存满,使得rwnd=0。在将rwnd=0告知给主机A后,如果主机B没有任何数据发送给主机A。会发生什么?

主机B的应用进程逐渐将缓存清空,TCP并不向A发送带有新的rwnd值的报文段(TCP当且仅当它有数据或有确认要发送才会发送报文段)。所以主机A并不知道主机B的缓存区有新的空间,导致主机A被拥塞不能在发送数据。

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

3.5.6TCP连接管理

(1)TCP连接的建立

假设运行在客户主机上的一个进程想与服务器主机上的一个进程建立连接。客户应用进程首先通知客户TCP,客户TCP通过以下方式与服务器TCP建立一条TCP连接:

客户端的TCP首先向服务器端的TCP发送一个特殊的TCP报文段。这个报文段中不包含应用层数据,报文段首部中的SYN比特被置为1。客户会随机选择一个起始序号(client_isn)放置于起始TCP 的SYN报文段的序号字段中。这个报文段将会被封装在一个IP数据报中,并发送给服务器

服务器读取包含TCP SYN报文段的IP数据报,并为该TCP连接分配TCP缓存和变量,并向客户端TCP发送允许连接的报文段。这个报文段称为SYNACK报文段。这个允许连接的报文段不包含应用层数据。但包含三个重要信息:SYN比特被设置为1;TCP报文段首部的确认号字段设置为client_isn+1;服务器选择自己的初始序号(server_isn),并将其放入TCP报文段首部的序号字段中

收到SYNACK报文段后,客户也需要为该连接分配缓存和变量。客户主机向服务器发送另一个报文段,这个报文段对服务器允许连接的报文段进行确认。该SYN比特被设置为0。该三次握手的第三个阶段可以在报文段负载中携带客户到服务器的数据

在完成上述的三个步骤之后,客户与服务器就可以互相发送包括数据的报文段了。在之后的每一个报文段中SYN比特都将被置为0。

问题:为什么需要初始序号?为什么需要3次握手,而不是两次握手?

①对于TCP通信的双方,在进行数据传输之前,需要建立一个连接。这个连接其实是虚拟的,主要由一对套接字对,或者叫四元组来标识,即源IP、源端口号、目标IP和目标端口号。准确来说,还要加上个协议类型TCP。初始序号是为了防止历史报文被下一个相同四元组的连接接收,从而避免数据错乱;

但是即使客户端和服务端的初始化序列号不一样,也会存在收到历史报文的可能。如果每次建立连接客户端和服务端的初始化序列号都不一」,就有大概率因为历史报文的序列号不在对方接收窗口,从而很大程度上避免了历史报文

②为了建立连接,通信的双方都需要各发送一个SYN包,同时从对方接收一个ACK包。

从理论上讲,每一方都要一去一回,总共需要发送4个控制消息来完成连接的建立。

通常情况是,服务端在监听某个端口,客户端发送请求连接消息,然后服务端进行回应。由于服务端也需要向客户端发送SYN包,因此可以将SYN包和对客户端的ACK合并到同一个包,从而减少一次交互。

为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤
如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认

(2)TCP连接的拆除

参与一条TCP连接的两个进程中的任何一个都能终止该连接。当连接结束后,主机中的缓存和变量将被释放。

①当客户打算关闭连接,客户应用进程发出一个关闭连接命令。这会引起客户TCP向服务器进程发送一个特殊的TCP报文段。这个报文段首部中的FIN比特置为1 ②当服务器接收到该报文段后,就向发送方返回一个确认报文段 ③然后,服务器发送他自己的终止报文段,这个报文段首部中的FIN比特被置为1 ④最后该客户对服务器的终止报文段进行确认。

(3)TCP连接状态变化

建立新连接状态变化:在一个TCP连接的生命周期内,运行在每台主机中的TCP协议在各种TCP状态之间变迁。客户TCP从开始的CLOSED状态,到发送过SYN报文段后的SYN_SENT状态,最后到接收到SYN为1的报文段进入ESTABLISHED状态。

关闭该连接状态变化:客户TCP发送一个FIN比特位1的TCP报文段,进入FIN_WAIT_1状态。当接收到服务器的确认报文段后,进入FIN_WAIT_2状态。客户接收到来自服务器的FIN比特为1的报文段后,客户TCP对服务器的报文段进行确认,并进入TIME_WAIT状态。经过等待后,连接就会正式关闭,客户端的所有资源包括端口号将被释放。

如果一台主机收到一个TCP报文段,其端口号或源IP地址与该主机上的进行中的套接字都不匹配时,主机会向源发送一个特殊重置报文段,这个TCP报文段将RST标志位置为1。从而告诉源停止发送报文段。

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

拓展:SYN洪泛攻击

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

这种TCP连接协议为SYN洪泛攻击(SYN flood attack)提供了环境,洪泛攻击通过发送大量的TCP SYN报文段而不完成第三次握手,引发服务器不断为半开连接分配资源,导致服务器的连接资源消耗殆尽。

现在通过SYN cookie来防御这种攻击:

①当服务器收到一个SYN报文段时,服务器并不知道它是否合法,所以服务器并不为其生成一个半开连接。而是生成一个初始TCP序号,该序号是SYN报文段的源和目的IP地址与端口号通过一个只有服务器知道的复杂散列函数计算出来的值。这个初始序号被称为cookie。服务器则发送这种具有特殊初始序列号的SYNACK分组。服务器也不会存储该cookie或任何对应SYN的其他状态信息

 ②如果该报文段的用户源是合法的,则客户会返回一个ACK报文段。服务器借助cookie来判断是否与前面发送的SYN对应,如果该ACK报文段与较早的SYN报文段cookie值相同,服务器才会创建一个具有套接字的全开连接

③如果用户并没有返回一个ACK报文段,则初始的SYN并没有对服务器产生危害,因为服务器没有为其分配任何资源

3.6拥塞控制原理

在TCP中,丢包一般是当网络变得拥挤是由于路由器缓存溢出引起的。分组重传因此作为网络拥塞的征兆。因此需要了解为什么拥塞会带来问题,网络拥塞时如何在上层应用得到的服务性能中n冥想的显露出来?如何使用算法来减少或避免网络拥塞?

3.6.1拥塞原因与代价

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

前提假设:

        假设两台主机(A B)都有一条连接,且这两条连接共享源与目的地之间的单跳路由

        假设主机A中的应用程序以 λin 字节/秒的平均速率将数据发送的连接中。这些数据时初始数据,这意味着每个数据单元仅向套接字中发送一次。

        假设运输层协议:数据被封装并发送,不知能差错恢复、流量控制或拥塞控制协议

        假设路由器有无限大的缓存空间

        主机B的平均发送速度与A相同。主机A和主机B的分组通过一台路由器,在一段容量为R的共享是输出链路上传输。

以下图左图描述了每连接吞吐量与该链接发送速率之间的函数

当发送速率在0~R/2之间时,接收方的吞吐量等于发送方的发送速率,即发送方的所有数据经过有限时延之后到达接收方②当发送速率超过R/2时,吞吐量只能拿到R/2.这个吞吐量是由于两条连接之间共享链路容量造成的。链路完全不能以超过R/2的稳定状态向接收方交付分组。无论主机A和主机B的发送速率设置为多高,都不可能超过R/2的吞吐量

 取得每R/2的吞吐量看起来充分利用了链路,实际上当发送速率接近R/2时,平均时延会越来越大。当发送速率超过R/2时,路由器中的平均排队分组数就会无线增长。因此从吞吐量角度看,余小宁在总吞吐量接近R的状态也许是一个理想状态,但从时延角度看,却并不是一个理想状态

因此:当分组的到达速率接近链路容量时,分组会有巨大的排队时延

2、情况2:两个发送发和一台具有优先缓存的路由器

前提假设:

        假定路由器缓存的容量是有限的,当分组到达一个已满的缓存时会被丢弃

        假定每条连接都是可靠的,分组丢失后会被重传

        假定以 λin 字节/秒为应用程序将初始数据发送到套接字的速率

        假定运输层向网络中发送报文段(含初始数据和重传数据)的速率为  λ‘in 字节/秒,也称为网络的供给载荷

①假设主机A能够以某种方式获取路由器中的缓存是否空闲,从而仅当缓存空闲时才发送分组。在这种情况下将不会产生丢包,λin=λ‘in,连接的吞吐量=λin。以下图中a所示,从吞吐量的角度来看,性能是理想的,即发送的每个分组都被接收到。这种情况下平均主机发送速率不能超过R/2

②发送方仅在确认一个分组丢失时才重传。这种情况下的性能与下图b类似。当供给载荷λ‘in (初始数据的传输速度+重传速率)为R/2时。数据被交付给接收方应用程序的速率是R/3。因此再发送的0.5R单位数据中,从平均的角度收,有0.333R字节/秒是初始数据,而0.166R字节/秒是重传数据

因此:发送方必须执行重传以补偿因为缓存溢出而丢弃的分组

③发送方也许会提前发生超时并重传在队列中已经被推迟但是还未丢失的分组。在这种情况下,初始数据分组和重传分组都可能到达接收方。然而接收方只需要一份数据即可,导致路由器转发重传的初始分组副本是在做无用功,而路由器本可以利用链路的传输能力发送另一个分组。以下图c所示,假定每个分组被路由器平均转发两次时,其供给载荷接近R/2,吞吐量接近R/4

因此:发送方在遇到较大时延时所进行的不必要重传,会导致路由器利用其链路带宽来转发不必要的分组副本

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

前提假设:

        假定每台主机都采用超时/重传机制来实现可靠数据传输服务

        假定所有的主机都具有相同的λin值

        假定所有的路由器的链路容量都是R字节/秒

主机A->主机C的连接:该链接经过路由器R1和R2。A-C连接与D-B连接共享路由器R1,并与B-D连接共享路由器R2。

对于一个极小的λin值,路由器缓存的溢出是很少的,吞吐量大致接近供给载荷。对稍大的λin值,对应的吞吐量也更大,因为有更多的初始数据被发送到网络中并交付到目的地,溢出仍然很少。

因此,对于较小的λin,λin的增大会导致λout的增大

 对于一个很大的λin值,不管λin的值多大,到达路由器R2的A-C流量的到达速率最多是R,也就是从R1到R2的链路容量。如果λ’in对于各个连接来说都是极大值的话,那么在R2上B-D流量的到达速率可能会比A-C流量的到达速率大得多。因为A-C与B-D会在路由器R2上为有限的缓存竞争,所以当B-D供给载荷增加时,A-C在R2上的流量会越来越小。

因此:需要考虑供给载荷与吞吐量之间的权衡

每当有一个分组在第二跳路由器上被丢失时,第一跳路由器所做的转发就是无意义的。因此第一跳路由器用来转发分组到第二跳的传输容量用于传输不同的分组可以提高效率

因此:当一个分组沿一条路径被丢弃时,每个用于转发该分组的上游路由器的传输容量都被浪费

3.6.2拥塞控制方法

通过网络层是否为运输层拥塞控制提供显示帮助来区分拥塞控制方法

①端到端拥塞控制:在端到端拥塞控制方法中,网络层没有为运输层拥塞控制提供显式支持。即使网络中存在拥塞,也只能通过丢失与时延来获取信息。TCP采用端到端的方法解决拥塞控制,因为IP层不会向端系统提供有关网络拥塞的反馈信息。TCP通过使用增加的往返时延值作为网络拥塞程度增加的指示

②网络辅助的拥塞控制:路由器向发送方提供关于网络中拥塞状态的显式反馈信息。一般使用简单的一个比特来指示链路中的拥塞情况。ATM可用比特率 拥塞控制中,路由器显式的通知发送方路由器能在输出链路上支持的最大主机发送速率。

拥塞信息从网络反馈到发送方通常有两种方式:①直接反馈信息可以由网络路由器发给发送方,这种方式采用阻塞分组②路由器标记或更新发送方流向接收方的分组中的某个字段来指示拥塞的产生,这一种形式的通知需要经过至少一个完整的往返时间

3.7TCP拥塞控制

TCP必须使用端到端的拥塞控制而不是网络辅助的拥塞控制,因为IP层不向端系统提供显式的网络拥塞反馈。所以TCP采用的方式是让每一个发送方根据所感知到的网络拥塞程度来限制其能像连接发送流量的速率。如果TCP感知路径上没有拥塞,则会增加发送速率。如果感知到路径上有拥塞,则会减少发送速率。

这同时也带来了三个问题:①一个TCP发送方如何限制它向其连接发送流量的速率?②一个TCP发送方如何感知从它到目的地之间的路径上才能在拥塞?③当发送方感知到端到端的拥塞时,采用何种算法来改变其发送速率呢?

(1)TCP发送方是如何限制向其连接发送流量的?

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

LastByteSent - LastByteAcked ≤ min { cwnd , rwnd }

假设TCP接收缓存足够大,即rwnd足够大。在一个没有丢包和发送时延的连接小,每个往返时间(RTT)内,允许发送方向该连接发送cwnd个字节的数据,在RTT结束时发送方接收对数据的确认报文。因此发送方的发送速率大概是cwnd/RTT 字节/秒。

通过调节cwnd的值,发送方因此能够调整它向连接发送数据的速率

(2)TCP发送方如何感知它与目的地之间的路径上出现拥塞的?

TCP发送方发生”丢包事件“包括:出现超时,收到来自接收方的冗余ACK。当出现过度的拥塞时,沿着这条路径上的一台或者多台路由器的缓存会溢出,导致数据报被丢弃。从而引起丢包事件,发送方从而获取到拥塞指示。

如果网络上没有拥塞,TCP将以确认的到达作为一切正常的标识,并通过确认来增加窗口的长度(及其传输速率)。拥塞窗口增加的速率取决于确认到达的速率。TCP使用确认来触发增大它的拥塞窗口长度的行为,因此被称为自计时的

(3)TCP发送方如何确定发送速率,使得网络既不堵塞,也能充分能利用所有可能带宽?

一个丢失的报文段表意味着拥塞,因此当丢失报文段时应当降低TCP发送方的速率。对于一个特性报文段,如果出现一个超时事件或者四个确认(一个初始ACK和三个冗余ACK)则隐式表明减少发送速率

一个确认报文段指示该网络正在向接收方交付发送方的报文段,因此对先前未确认的报文段的确认到达时,增加发送方的速率。

带宽检测。TCP调节器传输速率的测量时增加其速率以响应到达的ACK,除非出现丢包事件,才减少传输速率。网络中没有明确的拥塞状态信号,而是通过ACK和丢包事件充当隐式信号,并且每个TCP发送方根据异步与其他TCP发送方的本地信息而行动

3.7.1TCP拥塞控制算法

详情可见RFC 5681。该算法包括3个主要部分:①慢启动②拥塞避免③快速恢复

慢启动和拥塞避免是TCP的强制部分,两者的差异在于对收到的ACK做出反应时增加cwnd长度的方式

1.慢启动

慢启动算法,每经过一个RTT,cwnd变为之前的两倍。发送方开始时发送initcwnd个报文段(假设接收方窗口没有限制然后等待ACK。TCP发送速率起始慢,但在慢启动阶段以指数增长

计算公式:cwnd = initcwnd * ( 2^n )

慢启动对于结束指数增长的处理方式:

如果存在一个由超时指示的丢包事件,TCP发送方将cwnd设置为1并重新开始慢启动过程。同时还会将第二个状态变量的值ssthresh设置为cwnd/2,即当检测到拥塞时将ssthresh置为拥塞窗口值的一半

②当检测到拥塞时ssthresh(“慢启动阈值”)设为cwnd的值一半,当到达或超过ssthresh的值时,继续使用cwnd翻番可能会造成拥塞,因此当cwnd的值为ssthresh时,结束慢启动并且TCP转移到拥塞避免模式

如果检测到3个冗余ACK,这时TCP执行一种快速重传,并进入快速恢复状态

慢启动优化方式TCP分岔:云服务性能优化

2.拥塞避免

正如前面所说,一旦TCP进入拥塞避免状态,cwnd的值大约是上次遇到拥塞的值的一半,距离再次拥塞的阈值并不遥远。所以TCP不能采用翻倍策略。

当cwnd<ssthresh时,拥塞窗口使用慢启动算法,按指数级增长。 当cwnd>ssthresh时,拥塞窗口使用拥塞避免算法,按线性增长。

因此TCP在每个RTT只将cwnd的值增加一个MSS。对于TCP发送方无论何时到达一个新的确认,就将cwnd增加一个MSS(MSS/cwnd)字节

例如:如果MSS是1460字节并且cwnd是14600字节,则在一个RTT内发送十个报文段。每个到达ACK增加1/10MSS的拥塞窗口长度,因此在收到对所有10个报文段的确认后,拥塞窗口的值将增加一个MSS

当发生拥塞的时候(超时或者收到重复ack),此时ssthresh需要更新为cwnd的一半,但是不小于两个MSS。此外,如果是超时引起的拥塞,则cwnd被置为initcwnd

超时重传对传输性能有严重影响。原因之一是在RTO阶段(Recovery Time Objective,他是指灾难发生后,从IT系统当机导致业务停顿之时开始,到IT系统恢复至可以支持各部门运作、恢复运营之时,此两点之间的时间段称为RTO)不能传数据,相当于浪费了一段时间;原因之二是拥塞窗口的急剧减小,相当于接下来传得慢多了。

3.快速恢复

对于引起TCP进入快速恢复状态的缺失报文段,对收到的每个冗余ACK,cwnd的值增加一个MSS

当丢失报文段的一个ACK到达时,TCP在降低cwnd后进入拥塞避免状态。如果出现超时事件,快速恢复会执行与慢启动、拥塞避免相同的动作,然后迁移到慢启动状态。当丢包事件出现时,cwnd的值被设置为一个MSS,ssthresh的值被设置为cwnd的一半

TCP TahoeTCP Reno
TCP早期版本。不论是发生超时指示的丢包事件,还是发生3个冗余ACK指示的丢包事件,无条件地将其cwnd减少至一个MSS,并进入慢启动阶段
  1. 收到第3个重复的ACK时,将ssthresh设置为当前cwnd的一半
  2. 设置cwnd=ssthresh+3
  3. 重传丢失的报文段
  4. 每收到一个重复的ACK,cwnd+1
  5. 确认新数据的ACK到达时,设置cwnd=ssthresh

如上图所示,阈值ssthresh初始等于8个MSS。在前8个传输回合,Tahoe和Reno采取了相同的操作。拥塞窗口在慢启动阶段以指数速度快速爬升,在第4轮传输时达到了阈值,然后拥塞窗口以线性速度爬升。直到第8轮传输后出现3个冗余ACK,此时丢包事件发生,拥塞窗口cwnd的值为12MSS。于是ssthresh的值被更新为0.5*cwnd=6MSS。

在TCP Reno下,拥塞窗口cwnd被设置为9MSS(cwnd=ssthresh+3MSS),然后线性增长

在TCP Tahoe下,拥塞窗口cwnd被设置为1MSS,然后呈指数增长,直到到达ssthresh值开始线性增长

4.TCP拥塞控制:回顾

假定丢包由3个冗余的ACK而不是超时指示,TCP的拥塞控制是:每个RTT内cwnd线性增加1MSS,然后出现3个冗余ACK事件时cwnd减半。因此TCP拥塞控制常常被称为加性增、乘性减(Additive-Increase,Multiplicative-Decrease,AIMD)拥塞控制方式

在TCP Reno之后,在RFC 3782 RFC 2018中提出了TCP Vegas算法。Vegas算法的基本思想:①在分组丢失发生之前,在源与目的地之间检测路由器中的拥塞②当检测出快要发生的分组丢失时,线性的降低发送速率。快要发生的分组丢失是通过观察RTT来预测的,分组的RTT越长,路由器中的拥塞越严重

5.对TCP吞吐量的宏观描述

接下来考虑一个长存活期的TCP连接的平均吞吐量。由于TCP慢启动阶段以指数级增长,时间非常短,所以忽略慢启动阶段。在一个特定的往返间隔内,TCP发送数据的速率是拥塞窗口与当前RTT的函数。

当窗口长度是 ω 字节,往返时间是RTT秒时,则TCP的发送速率大约是 ω/RTT 。于是TCP通过每经过1个RTT将 ω 增加1个MSS,直至下一次丢包事件发生。当一个丢包事件发生时,用 W 表示 ω 的值。

假设在连续持续期间RTT和W几乎不变,那么TCP的传输速率在W/(2*RTT)到W/RTT之间变化

当速率增长至W/RTT时,网络丢弃来自连接的分组;然后发送速率减半,进而每过一个RTT发送速率就增加MSS/RTT,直到再次到达W/RTT为止。这一个过程不断重复

6.经高带宽路径的TCP

3.7.2公平性

考虑K条TCP连接,每条都有不同的端到端路径,但是都经过一段传输速率为R bps的瓶颈链路。假设每条连接都在传输一个大文搭建,并且无UDP流量通过该段瓶颈链路。如果每条连接的平均传输速率接近R/K,即每条连接都的到相同份额的链路带宽,则认为该拥塞控制机制是公平的

TCP趋于在竞争的多条TCP连接之间提供对一段瓶颈链路带宽的平等分享

前提假设:

假设两条连接由相同的MSS和RTT(即有相同的拥塞窗口长度,相同的吞吐量)

假定它们有大量的数据发送,并且没有其他TCP连接或UDP数据报穿越该阶段共享链路

忽略TCP的慢启动阶段

假设TCP连接一直按照AIMD方式运行

如果TCP要在这两条TCP连接之间平等地共享链路带宽,那么实现的吞吐量曲线从原点沿45°方向平等带宽共享。理想情况下,两个吞吐量的和为R。所以吞吐量应当落在平等带宽共享曲线与全带宽利用曲线的交叉点附近。

A点:两条链路共同消耗的链路带宽量小于R,所以无丢包实现发生,根据拥塞避免算法,两条连接每过一个RTT都要将其窗口增加1MSS。因此向B前行,最终两条连接共同消耗的带宽将超过R,导致分组丢失

B点:两条连接都经历了分组丢失,于是按照二分之一减小其窗口,从而变成C状态。C位于B与原点连线上的一点。

C点:两条链路共同消耗的链路带宽量小于R,所以无丢包实现发生,再次向D方向前行

D点:两条连接再次减半

因此:两条连接实现的带宽最终将沿着平等高带宽共享曲线在波动

以上的推论都是建立在所有连接具有相同的RTT值,且对于一个主机-目的地之间只有一条TCP连接。然而实际上达不到这些要求,客户-服务器应用因此能获得非常不平等的链路带宽份额。当多条连接共享一个共同的瓶颈链路时,那些具有较小RTT的连接能够在链路空闲时获得更多的可用带宽(即更快的打开拥塞窗口)因而将比那些具有较大RTT的连接享用更高的吞吐量

1.公平性和UDP

由于TCP的拥塞控制机制,许多因特网电话与视频会议应用不采用TCP运行,因为即使在网络非常拥塞的情况下他们也不想其传输速率被限制。由于UDP没有内置的拥塞控制,所以这些应用采用UDP。如果在一个连接中同时具有UDP和TCP,UFP源很有可能压制TCP流量

2.公平性和并行TCP连接

当一个应用使用多条并行连接时,它占用了一条拥塞链路中较大比例的带宽。如果这个连接并行了很多TCP连接,会导致其他新的应用连接带宽分配较少。

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

RFC 1122中慢启动与拥塞避免开始标准化,TCP已经实现了端到端拥塞控制的形式

一个TCP发送方不会收到来自网络层的明确拥塞指示,而是通过观察分组丢失来推断拥塞

 在IP和TCP的扩展方案RFC 3168中,实现了网络明确向TCP发送方和接收方发出拥塞信号。这种形式的网络辅助拥塞控制称为明确拥塞通告(Explicit Congestion Notification,ECN)

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

然而在RFC 3168中并没有提供路由器拥塞时的定义,该判断是由路由器厂商所做的配置选择,并且由网络操作员决定。RFC 3168推荐仅当拥塞持续不断存在时才设置ECN比特

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/594510
推荐阅读
相关标签
  

闽ICP备14008679号