由[RFC 768]定义的UDP只是作了运输协议可以作的最少工做。除了复用/分解功能极少许的差错检测外,它几乎没有对IP增长别的东西。若是应用程序开发人员选择UDP而不是TCP,则该应用程序差很少就是直接与IP打交道。UDP从应用程序进程获得数据,附加上用于多路复用/分解服务的源和目的端口号字段,以及两个其余小字段,而后造成的报文段交给网络层。网络层将运输层报文段封装到一个IP数据报中,而后尽力而为地尝试将此报文交付给接收主机。若是该报文段到达接收主机,UDP使用目的端口号将报文段中的数据交付给正确的应用程序进程。html
值得注意的是,使用UDP时,在发送报文段以前发送方和接收方的运输层实体之间没有握手。正由于如此,UDP被称为时无链接的。算法
DNS是一个一般使用UDP的应用层协议的例子。当一台主机中的DNS应用程序想要进行一次查询时,它构造了一个DNS查询报文并将其交给DUP。无需执行任何与运行在目的端系统中的UDP实体之间的握手,主机端的UDP为此报文添加首部字段,而后将造成的报文段交给网络层。网络层将此UDP报文段封装进一个IP数据报中,而后将其发送给一个名字服务器。在查询主机中的DSN应用程序则等待对该查询的响应。若是它没有收到响应(多是因为底层网络丢失了查询或响应),则要么试图向另外一个名词服务器发送该查询,要么通知调用的应用程序它不能得到响应。小程序
为何开发人员宁愿在DNS目录服务器上使用UDP构建应用,而不选择TCP上构建呢?既然TCP提供了可靠数据传输服务,而UDP不能提供,那么TCP是否老是首选呢?答案是否认的,由于有许多应用更适合用UDP,缘由主要有:缓存
因此像网络管理(SNMP)、路由选择协议(RIP)、名字转换(DNS)。括号对应的是应用层协议,这些应用程序都在运输层采用了UDP协议。接着来看UDP报文段的结构,在此以前有必要说明如下,UDP的应用是能够实现可靠数据传输的。能够经过应用程序自身创建可靠性机制来完成,将可靠性创建于应用程序中可使其“左右逢源”,也就是说应用进程能够进行可靠通讯,而无需受制于由TCP拥塞控制机制和传输速率限制。服务器
应用层数据占用UDP报文段的数据字段。UDP首部只有四个字段,每一个字段有两个字节组成。经过端口号可使目的主机将应用数据数据交给运行在目的端系统中的响应进程(即执行分解功能)。长度字段指示UDP报文段中的字节数(首部加数据,字节为单位)。由于数据字段的长度在一个UDP段中不一样于在另外一个段中,故须要一个明确的长度,接收方使用检验和来检查该报文段中是否出现差错。实际上,计算检验和时,除了UDP报文段之外还包括IP首部的一些字段,为了讨论检验和的计算,暂时忽略。网络
UDP检验和:并发
UDP检验和提供了差错检测功能。也就是说,检验和用于肯定UDP报文段从源到达目的地移动时,其中的比特是否发生了改变。发送方的UDP对报文段中的全部16比特字的和进行反码运算,求和时遇到的任何溢出都被回卷。获得的结果被放在DUP报文段中的检验和字段。如何计算UDP/TCP检验和框架
虽然UDP提供差错检测,但它对差错恢复无能为力,UDP的某种实现只是丢弃受损的报文段,其余市县是将受损的报文段交给应用程序并给出警告。函数
考虑可靠数据传输的问题,不只仅是在运输层,也会出如今链路层。可靠数据传输的框架,为上层提供的服务抽象是:数据能够经过一条可靠的信道进行传输。借助于可靠信道,传输数据比特就不会受到损坏或丢失,并且全部数据都按照其发送顺序进行交付。这刚好就是TCP向调用它的因特网应用所提供的服务模型。性能
TCP是在不可靠的(IP)端到端网络层之上实现的可靠数据传输协议,更通常的状况是,两个可靠通讯端点的下层多是由一条物理链路组成或是由一个全球互联网络组成。就可靠数据传输目的而言,能够将较低层直接视为不可靠的点对点信道。底层信道损坏比特或丢失整个分组时,须要什么样的协议机制,这贯穿咱们讨论始终假设分组将以它们发送的次序进行交付,某些分组可能会丢失,这就是说,底层信道不会对分组重排序。
上图简单的模拟传输协议接口。(rdt表示可靠数据传输协议,_send指示rdt的发送端正在表调用。udt表示不可靠的数据传输)
rdt_send()函数表示能够调用传输协议的发送方;
udt_send()表示发送端和接收端发送分组给对方;
deliver_data()表示rdt向叫高层交付数据的方法;
rdt_rcv()表示rdt从底层信道接收一个分组;
如今一步步地研究一系列协议,它们一个比一个复杂,最后获得一个无错、可靠的数据传输协议。首先,考虑最简单的状况,即底层信道是彻底可靠的,将此协议定义为rdt1.0。
1.0 经彻底可靠信道的可靠数据传输:rdt1.0
上图表示发送方和接收方的有限状态机(Finite- State Machine, FSM),上图(左)中的FSM定义了发送方的操做,上图(右)中FSM定义了接收方的操做。
上面的流程图描述了rdt1.0发送端的处理过程。
上面的流程图描述了rdt1.0接收端的处理过程。
虽然在rdt1.0中是基于一个理想中彻底可靠信道来实现的数据传输,可是也描述了运输层的基本功能就是负责网络层与应用层的数据传输,咱们将这个运输层协议先成为简单协议。在简单协议中,一个单元数据与一个分组没有差异,并且全部分组是从发送方流向接收方,有彻底可靠信道,接收不须要任何反馈信息给发送方。注意,咱们也假定了接收方与发送方的速率同样快。
2.0 经具备比特差错信道的可靠数据传输:rdt2.0
底层信道实际的模型是分组中的比特可能受损,分组的传输、传播或缓存的过程当中,这些比特差错一般出如今网络物理部件中。在讨论比特差错信道的可靠数据传输时,咱们假设全部发送的分组仍是按照顺序接收的。相较彻底可靠信道只有增长比特差错这一种状况。
从理论上来说,只须要将比特差错的分组识别出来,而后将差错信息反馈给发送方,让发送方将差错分组从新发送一次。在计算机网络中,基于这样重传机制的可靠传输一些被称为自动重传请求协议(ARQ)。ARQ协议中还须要另外三种协议功能来处理存在比特差错的状况:
理论上来讲,好像有ARQ协议就能够实现比特差错信道的可靠数据传输。发送方每传输一个分组给接收方,等待接收方反馈回信息,若是返回的是ACK就继续传输下一个分组,若是返回的是NAK,就从新传输上一个分组,这种行为又被称为停等协议。到这里,好像rdt2.0就能够实现经具备比特差错信道的可靠数据传输了,别高兴太早,仔细看看反馈信息是什么?它自己也是被信道传输的比特,怎么才能保证反馈信息的比特不出错呢?这是不可能的,由于物理传输受损是必然的,那要怎么解决呢?
考虑处理受损ACK和NAK的三种可能性:
解决这个新问题(第三种方法中的没法确认分组问题)的方法很是简单,在数据分组中添加一个新字段,让发送方对其数据分组编号,即将发送数据分组的序号放到该字段。重传的分组序号与最近接收到的分组序号相同,新的分组序号会变化(使用模2“前向”移动:模2运算)。目前咱们假定的是信道不会丢失分组,因此ACK/NAK分组自己不须要指明他们要确认的分组序号。发送方接收到ACK/NAK分组是为响应最近发送的数据分组而生成的。rdt2.1反映出目前正在发送的分组或但愿接收的分组的序号是0仍是1。rdt2.1使用了从接收方收到的确定确认和否认确认。当接收方收到失序分组时,发送确定确认。若是收到受损分组,则发送否认确认。若是不发送NAK,而是对正确接收到的分组发送一个ACK,那么也能获得与NAK同样的效果。发送方收到对同一个分组的两个ACK(接收到了冗余ACK)后,就能够知道接收方没有正确接收被确认两次的分组后面的分组。这也产生了协议rdt2.2。rdt2.2是在有比特差错信道上实现的一个无NAK的可靠传输协议,此时ACK报文就需明确所确认的分组序号。(这一段的具体实现不太明白《计算机网络》P141~143)。
3.0 经具备比特差错的丢包信道可靠数据传输:rdt:3.0
如今除了比特损坏外,底层信道还会丢包,这样的状况并不罕见。因此协议必须关注两个问题:怎么检测丢包以及发生丢包后该作些什么?
在rdt2.2中已经使用的技术有检验和、序号、ACK分组、和重传等。在这个基础上考虑结局丢包问题,丢包所形成的问题就是接收方没法响应,不会反馈信息给发送方,这里就有了一个突破口,就是延时时间,假设已知在不丢包的状况下接收方的反馈时间是n,那就能够采用倒计数定时器等待时间n后再次发送上次的分组,这一样会产生冗余数据分组,而这样的问题再rdt2.2中已经获得解决,因此丢包问题也就解决了。
3.1 流水线可靠数据传输协议 :rdt3.1
在rdt3.0中的以及2.2中都采用了停等协议,对信道的利用率很是的低(案例见《计算机网络》P144~146)。解决这个问题的简单方案就是:流水线可靠数据传输协议。流水线可靠数据传输协议采用发送多个分组(一样序号的一个分组发送多个)的方式来实现。
多个分组的运输原理是基于信道实际容量和单个分组传输的使用比率来实现的,也就是假设使用停等协议传输方式只是用了信道传输容量的33%,那多分组传输就能够一次连续传输三个相同序列的分组,这样信道利用率就提升了3被,也就提升了分组的传输成功率。这样产生的连锁反应就是成功率提高下降了重传,下降了重传就下降了反馈比特损坏和丢失率,总体性能就会提升不少。
流水线可靠数据传输协议除了多分组传输,固然就是采用流水线的传输方式连续传输,那什么是流水线传输呢?为何要使用流水线传输呢?
采用多分组传输实现了很是贴近彻底可靠传输,就没必要要采用停等应答的低效方式来解决比特损坏和分组丢失,而是采用回退N步和选择重传的方式来解决比特损坏和分组丢失问题。在解析回退N步和选择重传的具体技术以前,先来看看流水线彻底可靠协议的基本实现逻辑:
从上面的流水线可靠传输协议示图中能够看到每个分组都会被发送屡次,这是流水线可靠传输协议的核心,只要多个分组中有一个没有损坏就能够实现了可靠传输。可是,也可能会出现极端的状况就是整组损坏的状况,在示图中我标识了重传反馈,其实不正确,只是为了区分如下整组丢失、反馈比特损坏致使的超时,其实质上都是使用选择重传来解决。在解析选择重传以前须要先来讲明如下回退N步(GBN)协议的原理,这是由于流水线可靠传输协议带来的下列影响形成的:
3.1.1 回退N步
在回退N步(GBN)协议中,容许发送方发送多个分组而不须要等待确认,可是也受限于在流水线中未确认的分组数不能超过某个最大容许数N。在流水线可靠协议示图中能够看到GBN协议的序号范围。若是将基号(base)定义为最先的未确认分组序号,将下一个序号(nextseqnum)定义为最小的未使用序号,则能够将序号范围分为四段:在[0,base-1]段内的序号对应于已发送并被确认的分组;[base,nextseqnum-1]段内对应已发送但未被确认的分组;[nextseqnum,base+N-1]段内的序号用于能够被当即发送的分组。若是有数据来自上层的话,最后大于base+N的序号不能被使用,知道当前流水线中未被确认的分组已获得确认。
随着协议进行,该窗口序号空间向前滑动,所以N常被称为窗口长度,GBN协议也常被成为滑动窗口协议。在此咱们限定的窗口长度N,而不是让分组数为无限大是有两个缘由①流量控制②TCP拥塞控制。若是分组序号字段的比特数为k,那么序号范围就是[0,2^k-1],在一个有限的序号范围内,全部涉及序号的运算必须使用模2^k运算。
GBN发送方必须响应三种类型的事件:
下图表示了GBN的运行模式:
GBN协议中综合了可靠数据传输协议构件的全部技术,这些技术包括使用序号、积累确认、检验和超时/重传操做。采用GBN这种协议看似好像很合理很实用,可是却有一个很是大的闭端,随着协议的运行,重传的分组就会积累的越多,看到上面的示图就一目了然,后面的重传分组和正常分组都同样多了,并且随着时间推移,重传会更加频繁,因此后面就有了选择重传来解决这个问题。
3.1.2 选择重传
GBN也存在着一些性能问题,单个的分组出现差错就会引发GBN重传大量没必要要重传的分组。在信道差错率很高时,流水线可能会被没必要要重传的分组所充斥。可操做此处SR Java小程序查看SR运做流程。
SR协议经过让发送方仅重传那些它怀疑在接受方出错(丢失或受损)的分组而避免没必要要的重传。
下图(来自《计算机网络 自定向下方法》)显示了SR协议中发送方和接收方的序号范围。
在SR协议中发送方和接收方所采起得动做可见下文描述。
SR发送方的事件与动做
从上层接收到数据
从上层接收到数据后,SR发送方检查下一个可用于该分组的序号。若是该序号位于发送方的窗口内,则将数据打包并发送;不然就像再GBN中同样,要么将数据换组,要么返回给上层以便之后传输。
超时
定时器在此用来防止丢失分组。可是,SR中每一个分组都要有本身的逻辑定时器。
收到ACK
若是收到ACK,假若该分组序号在窗口内,SR发送方就将那个被确认的分组标记为已接收。
若是该分组的序号等于send_base,则窗口基序号向前移动到具备最小序号的未被确认分组处。
若是窗口移动了而且有序号落在窗口内的未发送分组,则发送这些分组。
SR接收方的事件与动做
SR接收方将确认一个正确接收的分组而无论其是否按序。失序的分组将被缓存,知道全部丢失分组皆被收到为止,这时才将一批分组按序交付给上层。
序号在[rcv_base,rcv_base+N-1]内的分组被正确接收
在此状况下,收到的分组落在接收方的窗口内,一个选择ACK被回送给发送方。
若是该分组之前没有被接收到过在,则缓存该分组。
若是该分组的序号等于基序号,则该分组以及之前缓存的序号连续的分组交付给上层。
而后,接收窗口按向前移动分组的编号向上交付这些分组。
其余状况,忽略该分组
SR协议中发送方窗口和接收方窗口并不老是一致的。这会引出关于序号范围的一个问题。
在有限的序号范围的实现里,若是SR接收方窗口太大而且发送方和接收方窗口间的不一样步,便会形成发送方这边新分组序号与旧分组序号重复使用。致使没法辨析该序号表明的是一个新分组仍是旧分组。
SR的窗口长度应限制在小于等于序号空间大小的一半。
小结一下可靠数据传输机制中使用到的技术:
检验和、定时器、序号、确认、否认确认、窗口/流水线
TCP被称为面向链接的协议,这是由于在一个应用进程能够开始向另外一个应用进程发送数据以前,这两个进程必须先相互“握手”,即它们必须相互发送某些预备报文段,以创建确保数据传输的参数。做为TCP链接创建的一部分,链接的双方都将初始化与TCP链接相关的许多TCP状态变量。这些变量将会是控制实际数据传输的重要逻辑变量,在介绍TCP实际运输逻辑以前,先来看一下TCP协议执行发送和接收的基本结构(缓存)示图:
看到上面这个图你必定会很惊讶,为何与博客的第二部分“可靠数据传输协议”差异那么大?这是一个很关键的问题,在第二部分中说的可靠数据传输协议都是已分组传输为传输基本单元,可是须要注意的是,在TCP协议中传输的基本单元是用数据流来描述的,虽然本质上都是报文段,可是这两个描述差异将是TCP协议一切的起源(我的理解),从分组到数据流其主要的差异就是分组是从应用层直接调用运输层的接口实现,而后就直接被用来传输,在第二部分中出现的冗余是直接采用丢弃的方式来解决,甚至当分组出现错序的后面全部分组都被丢弃,这种粗暴的作法必然带来的就是增长了网络传输压力,浪费传输资源,结果就是传输效率低。而TCP协议采用了缓存的方式来解决这个问题,固然可靠数据传输的其余技术:检验和、定时器、序号、确认、否定确认、窗口/流水线、重传机制都被TCP做为基础而应用。实质上,TCP协议就是在写基础技术进一步优化,以达到可靠数据传输的最佳应用方案。
TCP提供的是全全双工服务(full-duplex-service),而且TCP链接也是点对点(piont-to-piont)的,这就说明TCP链接是单个发送方与单个接收方之间的链接。在一次发送操做中,从一个发送方将数据传给多个接收方,即“多播”操做对TCP来讲是不可能的。
先就示图的基本逻辑来分析TCP从链接到数据传输的过程:
最大限制长度的数据(MSS):一般根据最初肯定的由本地发送主机发送的最大链路层帧长度(最大传输单元)来设置。设置最大传输单元主要依据以太网和PPP链路层的最大链路层帧决定。假设链路层最大链路帧是1500字节的MTU,而TCP报文首部长度一般是40字节,所以MSS的典型值为1460字节。
TCP报文段的结构与UDP同样,首部包括端口号和目标端口号,它被用于多路复用与多路分解或用来将数据送到上层的应用层。报文的数据部分就不解释了,就是上层应用层的报文,这里重点来关注TCP的首部结构。
数据偏移:TCP中数据的开始处距离TCP报文段的起始位置有多远 == TCP报文段的首部长度。表示长度以32位比特为单位,所以最大能够表示60字节(15*4)的首部。保留占位6之后使用。
标志字段 | 含义 |
---|---|
URG | URG=1,用来指示报文段里存在着被发送端的上层实体置为“紧急”的数据。此时紧急指针有效 |
ACK | 当ACK=1时,确认号字段有效,表示对已被成功接收的报文段的确认 |
PSH | 当PSH=1时,指示接收方应当即将数据交付给上层,不用等接收缓存满了才交付 |
RST | RST和下面的SYN、FIN用于TCP创建链接和释放链接。 RST用于①RST=1,TCP链接初出现严重差错,必须释放链接而后从新创建运输链接 ②拒绝一个非法报文段或者拒绝打开一个链接 |
SYN | 在TCP链接创建时用来同步序号 |
FIN | FIN=1,释放TCP链接 |
序号与确认号:
在开始介绍TCP时我就重点的描述了TCP的缓存和字节流,TCP把数据当作无结构的、有序的字节流。从TCP的序号上就能够看出这一点,序号是创建在字节流上,而不是创建在报文字段的序列之上,报文的序号是该报文首字节的字节流编号。假设数据流由一个包含500000字节的文件组成,其MSS为1000字节,数据流的首字节编号是0,TCP将该数据流构建500个报文段,给第一个报文段分配序号0,第二个报文段分配序号1000,第三个报文段分配序号2000,以此类推。
将字节编号做为序号有什么好处呢?接着来看确认号,假设由A、B两个主机,A向B请求了一个报文段编号为0~1000的全部字节,可是在发送的过程当中因为网络层和链路层的问题,A只接收到了0~536序号字段和900~1000的序号字段,这就出现了乱序的问题,一般解决这类问题有两个基本选择:一、接收方当即丢弃失序字段二、接收方保存失序字段,并等待缺乏的字节以填补间隔。显然第二种方法更有效,而这第二种方法就须要确认号来完成这样精确的问题,TCP会先将1~536序号的字段添加到字节流中,而后将900~1000的序号字段暂时缓存,并将536序号做为确认好反馈给B,这时候B就知道了应该从发送方的缓存中取出537字节开始的字节流给接收方发送,直到发送发送到899字节流序号的报文,接收方将900~1000的字节流合并到字节流中,而后反馈确认号1000表示数据所有接收完毕。
在第二部分的可靠数据传输协议中介绍了超时/重传机制,一样,TCP协议也应用了一样的机制,可是在第二部分并无就超时/重传的具体时间作任何讨论,TCP做为一个具体的可靠数据传输协议固然就必须对超时/重传的时间设定有一个明确的解决方案。RTT做为往返时间,超时设定值可能就要比RTT大。TCP的实现仅在某一时刻测量一次往返时间(SampleRTT),并且不会测量重传报文的往返时间([Kan 1987])。
因为路由器的拥塞和端系统负载的变化,这些报文段的SampleRTT值会随之波动,因此并不是一个典型值。为了估计一个典型的RTT,TCP协议采用了对SampleRTT取平均值的办法。一旦得到一个新SampleRTT时,TCP就会根据下列公式来更新Esti-matedRTT:
EstimatedRTT = (1 - a ) * EstimatedRTT + a * SampleRTT
EstimatedRTT的新值是由之前的Esti-matedRTT的值与SampleRTT新值加权组合而成的。在[RFC 6298]中给出的a参考值是a = 0.125(即:1/8),这时上面的公式变为:
EstimatedRTT = 0.875 * EstimatedRTT + 0.125 * SampleRTT
经过加权平均是为了获得一个更能反映网络当前的拥塞状况,统计学的观点讲,这种平均被称为指数加权移动平均。在TCP中除了估算RTT外,测量RTT的变化也是有价值的。[RFC 6298]定义了RTT误差DevRTT,用于估算SampleRTT通常会偏离EstimatedRTT的程度:
DevRTT = (1 - b) * DevRTT + b * | SampleRTT - EstimatedRTT |
注意DevRTT是一个SampleRTT与EstimatedRTT之间差值的EWMA。若是SampleRTT值波动较小,那么DevRTT就会很小。反之,若是波动很大,那么DevRTT的值就会很大。b的推荐值为0.25。
设置和管理重传超时间隔:
假设已经给出了EstimatedRTT值和DevRTT值,那么TCP超时间隔应该用什么值呢?超时间隔应该大于等于EstimatedRTT,不然,将形成没必要要的重传,可是超时间隔也不能比EstimatedRTT大太多,不然当报文段丢失时,TCP不能很快地重传该报文段,致使传输延时过大。并且当SampleRTT值波动较大时,这个余量应该大些。因此DevRTT就有用武之地了,计算重传超时间隔的公式:
TimeoutInterval = EstimatedRTT + 4 * DevRTT
在[RFC 6298]中推荐TimeoutInterval初始值为1秒,一样当出现超时后,TimeoutInterval值将加倍,以避免即将被确认的后继报文段过早出现超时,一旦报文段收到更新的EstimatedRTT后,TimeoutInterval就又使用上述公式计算。
TCP在IP不可靠的状况下尽力为服务建立一个可靠数据传输服务。TCP的可靠数据传输服务确保一个进程从其接收缓存中读出的数据流是无损坏、无间隔、非冗余和按序的数据流,即该字节流与链接的另外一方端系统发送出的字节流是彻底相同的。TCP提供可靠数据传输的方法在博客的第二部分有详细的技术功能描述。
TCP具体是如何提供可靠数据传输的其有三个主要事件:从上层应用程序接收数据、定时器、收到ACK。实际上其基本的技术都是创建博客第二部分描述的可靠数据传输协议的技术上,可是TCP相对第二部描述的技术应该进一步优化,下面来一段简单的TCP可靠数据传输处理流程和多种状况:
状况一:假设有A、B两个主机,A主机向B主机发送一个报文,报文段的序号是92,且含8个字节的数据。在发送该报文段以后,主机B准确的接收到了该报文的全部数据并给A主机发送了确认报文序号100。可是,确认报文在传输途中丢失,引起了A主机重发这段报文,而且也顺利的传输到了B主机,可是B主机本来就已经有了这段报文,因此直接丢弃重传的报文段。
状况二:A主机在给B主机发送第一段报文后,因为窗口长度容许继续发送后续报文,因此A主机又给B主机发送了第二段报文,序号是100,包含20个字节的数据。假设这两个报文都无缺的被B主机接收,可是B主机给A主机发送的第一段确认报文丢失,致使A主机启动重发,并刷新定时器,若是第二段确认报文顺利的在定时器刷新后的间隔事件内被A主机收到,A主机就不会发送第二段报文了,这就是TCP的接收缓存的做用。
状况三:一样是状况二的数据传输,而且第一段确认报文丢失,可是第二段确认报文在第一段报文间隔时间以前就被A收到了,A也启动第一段报文的重发机制了。
超时间隔加倍:
超时间隔加倍这种机制为了控制拥塞,这种方式不仅是存在TCP协议中,在以太网的CSMA/CD中也一样采用这种方式控制网络拥塞。这里还不详细介绍TCP的拥塞控制,后面会有详细TCP拥塞控制机制分析。可是在上面的TCP重传中已经引述出了超时间隔加倍,为了方便理解,就在这里阐述一下超时间隔加倍的原理机制。
好比在上面的例子中提到反馈报文丢失,TimeoutInterval就不是用EstimatedRTT和DevRTT的值来推算了,而是直接在原来的TimeoutInterval上加倍,而且若是第一次超时加倍后仍是没有收到反馈报文,发送方在超时后重传报文段而且在第一次加倍的基础上再次加倍。(初始值:0.75秒,第一次超时:1.5秒;第二次超时:3秒)。这样就有效的防止了过多的分组被传入从源到目的端之间的路劲上,致使更大的网络延迟。
快速重传:
超时触发重传存在的问题是超时周期可能相对较长,在这个时间里接收方可能会将超时报文段前一个确认报文重复反馈给发送方屡次,这时就会出现ACK冗余现象,若是在超时周期以内一个报文段的ACK冗余数量获得三个,发送方就不会等超时间隔来触发重传了,而是提早实现重传。这就是快速重传。([RFC 5681])
TCP是回退N步仍是选择重传
由于TCP的缓存机制,不须要回退N步所有重传,而是将超时或触发快速重传的报文段进行重传操做,重触发机制上来看很像GBN协议,可是并无像GBN那样回退N步,而是有选择的重传操做,因此也能够说是SR协议,可是SR协议会向窗口传入疑似丢包或比特损坏的报文段,这与快速重传很是相似,可是又并行存在超时重传的GBN机制。TCP协议得到了SR协议与GBN协议的优点,因此能够说是GBN协议与SR协议的混合体。
这里所谓的流量控制并非控制网络流量MSS,也不是拥塞机制,而是控制TCP缓存的流浪,TCP的缓存空间不能溢出。这里须要关注的几个值:
LastByteRead:接收方的应用程序从TCP缓存中读出的最后一个字节符。
LastByteRcvd:接收方从网络中接收并放入缓存的最后一个字节符。
LastByteSent :发送方传入网络的最后一个字节符。
LastByteAcked:发送方发送的字节符但未被接收方确认放入缓存中的最小字节符。
RcvBuffer:接收方的缓存空间。
rwnd:接收方空闲的缓存空间。
因此得出如下公式:
LastByteRcvd - LastByteRead <= RcvBuffer ------TCP不容许已分配的缓存溢出。
rwnd = RcvBuffer - [ LastByteRcvd - LastByteRead] ------- 接收方空闲的缓存空间等于分配缓存空间 - 已被占用的缓存空间(已被占用的缓存空间等于已读最后一个字节符减去已放入缓存的最后一个字节符)
LastByteSent - LastByteAcked <= rwnd ------ 发送方最后发送的最后一个字节符减去未被接收方放入缓存的最小字节符要小于接收方的可用缓存空间
关于TCP链接其实关于链接部分在前面已经屡次出现了,指示解除链接没有介绍过,可是其本质上是确认机制实现的线程释放。也没有太多东西,直接上图:
三次握手:客户端向服务端请求资源。
第一步:客户端向服务端发送一段特殊报文,请求链接。(标志位SYN设置为1;)
第二部:服务端接收到请求链接报文后,返回一段特殊报文给客户端,创建链接。(SYN被设置为1;确认字段被加一:client_isn + 1;)
第三步:客户端收到服务端的链接创建确认报文后,客户端带着请求资源必需要的数据(也能够不带数据)发送一段特殊报文给服务端。(确认字段被加一:client_isn + 1;(在前面的基础之上加一))
上面三个步骤就是三次握手的过程,正式开始传输数据的时候SYN会被设置为0,接着来看四次挥手过程,也就是释放链接的过程:
第一步:当客服端请求的数据所有接收到之后,客户端就会向服务端发送一个释放链接的报文段。报文中的FIN被设置为1。
第二部:服务端收到客户端的释放链接报文段后,向客户端发送一个确认报文段ACK。
第三步:服务端紧接着有向服务端发送一个释放链接的报文段,而且报文中的FIN也会被设置为1。
第四步:客户端接收到服务端的释放报文段后,又向服务端发送一个确认报文端ACK,告诉服务端收到了释放链接的确认报文。
4.1 出现拥塞
网络拥塞通俗的说就是网络传输需求大于网络传输能力,网络拥塞的三个通常性状况:
状况1、假设路由有无限大的缓存空间,发送端的发送速率好像就能够无限扩大,可是并不是如此,链路彻底中的排队分组也就会随着发送端的发送速率无限扩大,因为排队分组达到链路层的容量时,分组就会产生很大的排队延时,从而致使网络拥塞。
状况2、假设路由的容量是有限的,也就是当路由的缓存已满后就会丢弃后续被传入的分组,因为丢弃分组就会致使运输层重传,这就会进入一个恶性循环,丢弃越多,重传就会越多,延时就会越长,延时越长就会触发更多的重传,这种网络拥塞也能够说是超出供给载荷。
状况3、多个发送方在多个路由器之间的多跳路径,当其中一个路由其中了大量的传输容量时,途径这个路由的全部传输都会被拥塞。
4.2 拥塞控制方法
端到端拥塞控制:在这个方法中,网络层没有为运输层拥塞控制提供显式支持,即便网络中存在拥塞,端系统也必须经过对网络行为的观察来推断网络是否阻塞。TCP必须经过端到端的方法解决拥塞控制,由于IP层不会向系统提供有关网络拥塞的反馈信息。TCP报文的丢失(经过超时或3次冗余确认而得知)被认定是网络拥塞的一个迹象,TCP会相应的减小其窗口长度。在TCP拥塞控制的一些最新建议中,即便用增长往返时延值做为网络拥塞程度增长的指示。
网络辅助的拥塞控制:在网络辅助的拥塞控制中,网络层构件(即路由器)向发送方提供有关网络中拥塞状态的显示反馈信息。拥塞信息从网络反馈到发送方一般有两种方式:①直接反馈信息由网络路由器发给发送方,这种通知方式常采用了一种阻塞分组(choke packet)的形式(含义为:“我阻塞了”)②显示拥塞通知(Explicit Congestion Notification,ECN)。第二种是路由器标记或更新熊发送方流向接收方的分组中的某个字段来指示拥塞的产生。当接收方接收到这样的分后后,就会向发送方发送网络拥塞的通知。这种方式须要至少须要一个完整的RTT。使用网络辅助的拥塞控制例子可参见ATM ABR拥塞控制。
4.3 TCP拥塞控制
在TCP的拥塞控制机制上,TCP使用的是端到端的拥塞控制。即让每一个发送方根据感觉到的网络拥塞程度限制其能向其链接发送流量的速率。由此引起三个问题:1.TCP发送方如何限制它向其链接发送流量的速率。2.TCP发送方如何感知它到目的地之间的路径出现了拥塞。3.当发送方感觉到了端到端的时延使用何种算法来改善其发送速率。
4.3.1 TCP发送方如何限制它向其链接发送流量的速率?
TCP链接的每个端都有一个接收缓存、一个发送缓存、和几个变量组成。运行在发送方的TCP拥塞控制机制跟踪一个额外的变量,即拥塞窗口(cwnd)。TCP发送方经过cwnd来控制发送流量速率,也就是未被确认的数据流量不能超过cwnd,因此也必然不会超过rwnd(接收方空闲缓存空间)。
LastByteSent - LastByteAcked <= min{cwnd, rwnd}
上面这个公式就是经过拥塞窗口控制发送方的发送流量速率的基本原理,假设rwnd无限容量,可是发送流量速率受到已发送发送未确认分组(已发送的最大字节符序号减去未被确认的最小字节符序号)的控制,也就间接的限制了发送流量速率。拥塞窗口长度校验算法
因此发送方的发送流量速率能够估算为:在不考虑丢包和发送时延的状况下,发送速率大概是cwnd/RTT(字节/秒)。
4.3.2 TCP发送方如何感知它到目的地的路径出现了拥塞?
假设将一个TCP发送方的“丢包事件”定义为:要么出现超时,要么收到来自接收方的3个冗余ACK。当出现过分的拥塞时,沿着这条路径上的一台路由缓存就会溢出,引起数据包被丢弃,丢弃数据包引起的丢包事件要么超时或收到3个上一个报文段的冗余ACK。因此发送方就认为在发送方到接收方的路径上出现了拥塞。
从判断窗拥塞中能够反向思考,若是发送方传输的报文段都正常被接收方接收到,也就是说都能正常的接收到接收方反馈的确认报文ACK,这样的状况下就能够被断定为时网络传输通畅,发送方就会增长拥塞窗口的长度,从而达到提升传输速率的效果,而却会根据反馈确认报文的ACK的RTT来判断网络通畅程度,若是确认已至关慢的速率到达就,速率增加也一样会以至关慢速度增加。反之,若是确认相对快的速率到达,拥塞窗口就会瞬间增大窗口长度。TCP把这种机制叫作自计时。
4.3.3 当发送方感觉到了端到端的时延使用何种算法来改善其发送速率?
概述了TCP拥塞控制后,如今就须要采用对应的方法来改善发送速率,广受赞誉的TCP拥塞控制算法[Jacobson 1988]。该算法包含了三个重要的部分:一、启动慢;二、拥塞避免;三、快速恢复。慢启动和拥塞控制是TCP的强制部分,二者的差别在于对收到的ACK作出反应时增长cwnd长度的方式。慢启动比拥塞控制能更快的增长cwnd的长度。快速恢复是推荐部分,对TCP发送方并不是必须的。
4.3.3.1 慢启动
在慢启动状态,cwnd的值以一个MSS开始并当传输的报文首次被确认就增长一个MSS。以下图所示,开始发送一个报文段,收到确认后拥塞窗口增长1。而后传输2个报文段,收到2个确认后增长拥塞窗口变成了4个MSS。这样没通过一个RTT,发送速率就会翻番。因而,TCP发送的起始速率慢,可是在慢启动阶段会以指数增加。
可是这样会的增加什么时候终止呢?慢启动对这个问题提供了几种答案。
第一种: 若是出现一个有超时引发的丢包事件(即网络中出现了拥塞),TCP发送方将cwnd设置为1并从新开始慢启动过程。它还会将第二个状态变量ssthresh(“慢启动阈值”)设置为cwnd/2。
第二种: 与ssthresh相关。当增长到cwnd=ssthresh时,结束慢启动并开始拥塞避免。
第三种: 若是检测到3个冗余ACK,这时TCP执行快速重传进入快速恢复状态。
4.3.3.2 拥塞避免
进入拥塞避免状态后,cwnd的值大约是上次遇到拥塞时的值的通常,即距离拥塞可能并不遥远。TCP可定不能再像慢启动那样对cwnd的值翻番,而是采用了另外一种方式更新cwnd的值。当TCP发送方不管什么时候达到一个新的确认,就将cwnd增长一个MSS字节(MSS/cwnd)。例如,若是MSS是1460个字节而且cwnd也是1460字节,则在一个RTT内发送10个报文段。每一个到达ACK增长1/10MSS的拥塞窗口长度,所以,在收到全部10个报文端的确认后,拥塞窗口的值将增长一个MSS。
那拥塞避免的线性增加在何时中止呢?跟启动慢同样,再出现丢包事件后cwnd的值一样会被更新为cwnd值的一半。若是丢包事件是由三个冗余ACK事件触发,在这种状况TCP会进入快速恢复状态。
4.3.3.3 快速恢复
在前面的TCP可靠数据传输部分就有提到快速重传,至关因而快速恢复的开始。在快速恢复中,对引发TCP进入快速恢复状态的缺失报文段,对收到的每一个冗余的ACK,cwnd的值增长一个MSS。最终,当丢失报文段到达时,TCP再下降cwnd后进入拥塞避免状态。若是出现超时事件,cwnd置为1个MSS,而且ssthresh置为cwnd的一半,迁移到慢启动。
快速恢复是TCP推荐部件而不是必需。一种早期的TCP版本TCP Tahoe,无论是超时而引发的丢包仍是3个冗余ACK引发的丢包事件,都会将cwnd置为1个MSS,并进入慢启动阶段。TCP较新的版本TCP Reno综合了快速恢复算法。