计算机网络 第五章 运输层

运输层属于计算机网络中基本是最难的部分了,这一章主要是TCP的拥塞控制和流量控制,这两个控制的过程存在很多且很复杂的细节。

5.1 运输层提供的服务

运输层为上面的应用层提供通信服务,从结构上看,属于面向通信部分的最高层,同时也是用户功能中的最低层。运输层工作在网络层之上,为运行在不同主机上的进程之间提供了逻辑通信,而网络层是提供主机之间的逻辑通信。
在这里插入图片描述
只有主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时只用到了下三层的功能。所以可以认为,运输层主要提供几个服务:
①进程之间的逻辑通信
与网络层不同,这一层的逻辑通信是进程之间的,而网络层是主机之间的。
②分用复用。
需要注意的是,运输层的分用复用与网络层中的分用复用并不一样。前者指的是发送方不同的应用进程都可以使用同一个运输层协议传送数据并在接收方的运输层正确交付到目的进程,而后者则是指发送方不同协议的数据都可以封装成IP数据报发送出去并在接收方交给相应的协议。
在这里插入图片描述
③差错检测
检测首部和数据部分。
④提供两种不同的传输协议
即面向连接的TCP和无连接的UDP。这两类传输协议是这一章的重点,这里先简单点一下,TCP面向连接,所以在传送数据之前必须先建立连接,通信过程中还需要实时监控和管理,最后再释放。这就给通信带来了很大的负担。而UDP采用无连接的传输,虽然不可靠,但是在时间效率上比TCP优秀很多,所以两者在实际使用时各有利弊,会根据通信类型来确定。

运输层向上屏蔽了低层网络的具体细节,从而使得进程看见好像确实有一条线路。此外,在使用TCP时,尽管下面的信道是不可靠的,但是借助TCP的确认重传机制,还实现了在不可靠信道上进行可靠通信的功能。

每一层都有一个地址,数据链路层是MAC地址,网络层时IP地址,到了运输层,这一层的地址是端口,通过端口来标识主机中的应用进程。由于进程的创建和撤销都是动态的,所以发送方几乎无法识别其他机器上的端口号,这也就意味着不能像低层那样采用一个完全固定的地址编号。
端口主要用端口号来标识,长度为16位。与前面的地址不同,端口号只具有本地意义,即端口号只标识本计算机应用层中的进程,而互联网上不同计算机的相同端口号是没有联系的。
端口号根据范围可以划分为两类:
①服务器端使用的端口号
这里又分为两小类。数值在0-1023之间的为熟知端口号,IANA提前分配给TCP/IP协议的一些重要程序的端口,这部分所有用户都有且所有用户都知道。此外,数值为1024-49151之间的部分为登记端口号,这部分的端口号也需要在INAN登记,提供给没有熟知端口号的应用程序使用,登记主要是为了防止重复。
②客户端使用的端口号
数值范围在41952-65535之间的为这一类,通过端口号来标识区分一台主机的不同进程,可以看出客户端使用的端口号并不如服务器端多,这是因为个人也就是客户端的计算机能力有限,分配太多用不到,而服务器由于其性能远大于客户端,所以分配给更多的端口号而且固定。

TCP采用套接字来识别端点。所谓套接字实际上就是一个通信端点,是用主机的IP地址后面接上端口号来构成的,这种结构可以唯一表示网络中的一台主机的一个应用进程。

5.2 用户数据报协议UDP

UDP是运输层较为简单的一个协议,因为它仅在IP的数据报服务上增加了两个最基本的服务:复用分用和差错检测,如果选择的是UDP,那么基本就相当于直接和IP打交道。
第一节提到过,UDP并不是可靠的,但是仍然有很多程序选择采用UDP,主要还是因为UDP简单的特点。UDP无需建立连接、无连接状态、分组首部开销小而且由于没有拥塞控制可以更好地控制数据的发送。
对于视频通话这类多媒体应用,偶尔错一点并不会对整个服务产生很大的影响,而对时间的及时性更加看重。就好比你和朋友打视频电话,出错那么几个像素点并不会影响你两个人的通话,但是如果让整个画面一点错都没有,代价是很容易卡,那么必然会对通话产生很大的影响。同理,如果传输的是一个文件,文件必须要求一点错都不能有,一旦错了就成了别的东西了,此时传输占据的时间就不是那么重要,反而对正确性要求更高,此时采用可靠的TCP进行传输是更好的选择。

UDP主要有以下的特点:
①UDP是无连接的,发送之前不需要先建立连接。
②UDP提供尽最大努力的交付,不保证可靠交付,但这并不意味着对数据的要求是不可靠的,所有维护传输可靠性的工作都在应用层完成。
③UDP面向报文,对于应用层交下来的报文,添加运输层首部就送给网络层,不合并、不拆分,相应的在接收方,UDP对上交上来的UDP用户数据报拆掉首部后就直接上交应用层。简单来说就是怎么来怎么给别人。
在这里插入图片描述
④UDP没有拥塞控制,网络出现的拥塞不会导致主机发送速率降低。
⑤UDP支持一对一、一对多、多对一和多对多的交互通信。
⑥UDP首部开销小

UDP数据报的结构很简单,UDP的首部格式如下:
在这里插入图片描述
UDP的数据报分为两部分:UDP首部和用户数据。UDP之后传到网络层作为数据部分组成IP数据报。UDP的首部有四部分组成:
①源端口
在需要对方回信的时候需要填入,如果不需要可以全填0.
②目的端口
③长度
这里的长度指的是UDP数据报的长度,即首部和数据的总长度,最小值为8,此时相当于只有首部而没有数据部分。
④校验和
这一部分是UDP数据报结构中最重要的部分。与一般的校验和获取方法有所不同,运输层的校验和获取时,需要补充一个伪首部,这个伪首部的结构如上图所示。其中第三个字段没有用,填0。而第四个字段填17表示这个数据报时UDP的。引入的伪首部,只在求检验和的时候才会用到。补充伪首部后,采用十六位反码校验,和网络层的方法一致。采用补充伪首部的方法,既校验了TCP&UDP用户数据的源端口号和目的端口号以及TCP&UDP用户数据报的数据部分,又检验了IP数据报的源IP地址和目的地址。伪报头保证TCP&UDP数据单元到达正确的目的地址。
伪首部不进行传输,只作为求检验和的一部分,用完就没有了。采用这种简单的差错检验方法,虽然检错能力并不是很强,但是简单而且处理速度快。
在这里插入图片描述

5.3 TCP的基本概念

TCP特别的复杂,放在一节里面太多,所以拆成六节来整理,每一节干货都很多。这一节主要是TCP的一些基本概念及特点。

TCP主要有以下的特点:
①TCP是面向连接的运输层协议。这个特点对应于后面的运输连接管理,TCP通过三次握手建立连接,之后通过四次握手释放连接,从而保证整个链接的稳定性和完整性。
②每一条TCP连接都只能连接两个端点,即只能点对点。
③提供可靠交付的服务,无差错、不丢失、不重复且按序到达。这里对应于后面的可靠控制,TCP通过确认重传机制来在不可靠的信道上进行可靠的传输。
④提供全双工通信。通信双方只要建立连接,就可以在任何时候发送数据,双方都有缓存,用来接收临时信息。为了简化模型,后面大多数情况下都是视为单工通信,但实际上是全双工的。
⑤面向字节流。这是TCP最重要也是最独特的特点。
所谓字节流,指的就是TCP将应用程序交下来的数据仅看作一连串的无结构的字节流,虽然是字节流,但是两台主机之间的TCP交互仍然是采用报文的格式,如下图:
在这里插入图片描述
为了实现可靠传输,需要对字节编号,从图里可以看出,传给TCP的是字节流,但是一次发送几个字节是不固定的,每次传入TCP或者传出TCP的字节数也是不确定的,这就提供了进行流量控制的基础。对于报文大小是不作限制的,但是要保证所有字节数是正确的,即TCP收到的报文数是不确定的,但是字节数是确定的。
这个特点可以用一个例子来理解,这个例子想了很久,后面也是通用的。我们可以将发送方看做后厨,而应用进程就是等着上菜的顾客,TCP连接是上菜的服务员,后厨做好菜以后就放到台子上等着服务员给顾客送过去,分几次送、每次上几个菜后厨都不管,但是一定要让菜按前菜-主餐-甜点的顺序给顾客而且一道也不能少,这样顾客才能按顺序吃下肚。这个例子在后面还会再用,是一个很万能的例子。

TCP把连接作为最基本的抽象,前面提到TCP连接的两个端点就是套接字,即端口号拼接到IP地址后面,表示的时候两个地址之间用冒号或者逗号隔开,有下面的形式:
在这里插入图片描述
而每一条连接唯一地被通信两端的两个端点所确定,即:
在这里插入图片描述

5.4 TCP的报文格式

前面提到过TCP面向字节流,但传输仍然是用报文。报文分为首部和数据两部分。其中,首部的前20个字节是固定的,后面有4n字节是根据需要而变化的,因此最短为20字节。
在这里插入图片描述
从图里可以看出,TCP报文的格式是所见的几个报文格式中最复杂的,正是由于这种复杂的结构,才实现了TCP那么多复杂的机制,尤其是确认部分和六个位,搞清楚这几部分的含义才能更好地理解后面的控制。
首部固定字段部分的含义如下:
源端口和目的端口:各占两字节,分别写入源端口号和目的端口号,与UDP类似,以此来实现分用复用。
序号:占4字节,是可靠控制实现的重要组成部分,在TCP中,需要对每个字节进行编号,而将字节打包发送时,需要将报文中第一个字节的编号填入这个字段,所以这个字段也称为报文段序号。
确认号:与序号相对,也是4字节的长度,这个字段的含义是期望收到对方下一个报文段的第一个数据字节的序号。这个字段很容易混,因为它指的不是上次传输最后一个,而是希望收到的,也就是说,如果确认号是N,那么就表示前面编号到N-1的字节已经送到了接收端,接收端希望发送段下一个发送的报文的第一个字节的编号是N。
数据偏移:占4位,表示的实际上就是首部长度,需要注意的是这个字段是以4字节为单位的,这也正好对应了帧长度必须是四字节的整数倍的限制,其原理与前面IP中长度字段原理一样。
保留:作为保留,暂时还没有用处。
URG位:即urgent,用于表示紧急数据,需要和后面的紧急指针字段配合使用。将这一位设置为1,表示发送方传下来了一个紧急数据,要求赶紧传送不能拖,一般来说字节流进入发送方缓存之后,什么时间发送是由TCP决定的,进程不能决定,所以使用这一位之后,不管现在缓存里面有多少,将紧急数据放在前面然后全部打包发出去。
ACK位:即acknowledge,用于表示确认位是否有效,只有这一位为1的时候确认号字段才有效,TCP规定连接建立之后的所有传送的报文段都必须把ACK设置为1。
PSH位:即push,作用于URG类似,只不过PSH的作用对象是接收方,一旦这一位设置为1,接收方在收到这个报文之后就尽快交付给应用进程,而不是像平时那样等到缓存满了再递交上去。
RST位:即reset,主要用于复位,当TCP连接中出现严重错误时,就必须利用这一位来释放连接重新建立连接。
SYN位:即synchronization,用于在建立连接时同步双方的序号,当SYN=1而ACK=0时表示这是一个连接请求报文,这一位在后面三次握手中会用到。
FIN位:即finish,用于释放连接,FIN=1时表示发送这个报文段的一方数据已经发送完毕,请求释放这一方的连接。
窗口:占两字节,这一字段表示的就是发送这个报文的一方的接收窗口的大小,窗口值告诉对方:从本报文段首部中的确认号算起,目前允许对方接收的数据量。这主要是因为接收方数据缓存是有限的,利用这个字段来进行流量控制。这一字段是在实时变化的,在流量控制中起着重要作用。
检验和:占两字节检验的方式和UDP一样,也是补充伪首部之后采用十六位反码检验。
紧急指针:与URG位搭配使用,用于指明本报文段中紧急数据的字节数,前面提到过URG=1会让发送方把紧急数据放在前面然后立即发送,这一位就是指明放在前面的紧急数据有多长,从而方便接收方快速找到紧急数据。
选项:长度可变,最长可达40字节,主要是用于提供一些额外功能。TCP最初只规定了一种选项,即最大报文段长度MSS,即每一个TCP报文段中数据字段的最大长度,用于协调收发双方减少IP分片的次数。后来又出现了选择确认、时间戳、窗口扩大等选项。

TCP这种复杂的报文结构,才使得其具有后面这么多强大的功能。

5.5 TCP的可靠控制

我们知道,运输层下面都是不可靠的信道,理想的传输条件下必须满足传输信道不产生差错并且不管以多快的速度发送,接收方都可以接收并且来得及处理。但实际网络中这样理想的传输条件是不存在的,必须要采用一些可靠的协议,在不可靠的信道中实现可靠的传输。这一节的协议就是解决这个问题的。

最原始的情况下,只要一次发送一个分组,收到接收方确认之后再发送下一个,这样就可以实现可靠的传输。需要指明的是,TCP支持全双工,连接双方可以同时收发,所以为了简化模型,这里的叙述全部是按照单工,即一方发送一方接收。
这种简单情况称为停止等待协议,该协议在无差错情况下,一方发送,发送完一个分组就停止发送,等待接收方的确认,只有收到了对方的确认才可以进行下一个报文的发送。如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210205115044451.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzg0OTUwNQ==,size_16,color_FFFFFF,t_70
如果接收段发现传输出错,就丢弃收到的分组,不做其他处理,发送方设置了一个超时重传计时器,一旦计时器规定时间内没有收到接收方发来的确认报文,就重传分组,这也就要求发送端要有一定的缓存来存储刚刚发送的分组,只有收到确认信息才可以把分组副本删除。除此之外,确认报文也可能出现错误,主要是两类:确认丢失和确认迟到。
从名字就可以看出,这两类分组主要是丢失和迟到的问题。确认丢失是指因为网络问题导致确认报文丢失,此时接收端已经收到了分组,但是发送端误认为自己的分组丢失接收端没有给出确认报文,只能重传分组,相当于接收端会收到两次同一个分组,此时解决方案是接收方直接丢弃,不向上层交付,但是向发送端发送确认,如下图所示:
在这里插入图片描述
而对于确认迟到,指的主要是由于网络的拥塞,分组经过了很久才到达发送端,但是到达时已经超过了超时重传计时器设置的时间,所以发送端已经重传了分组,相当于接收端还是会收到两个一样的分组。解决方法是发送端收下迟到的确认但是什么也不做,接收端丢弃重传的分组并重传一个确认报文。如下图所示:
在这里插入图片描述继续使用前面提到的后厨上菜的例子,我们可以将发送方看做后厨,接收方看做顾客,端菜的服务员就是传送信道。服务员手脚不干净,有时候偷吃有时候偷偷把菜丢掉,为了防止客人吃不到饭,后厨每次只做一道菜,没有收到顾客吃完的空盘子就不做下一道菜,并且一定时间内不看到空盘子,就认为服务员偷吃了,重新做一道给顾客端上去。这个例子就很好地表示了超时重传的机制,按照这个道理,确认丢失可以看作服务员把吃剩的空盘子扔了,后厨重新做了一道交给了顾客,顾客一看吃过了不想再吃,就把菜倒掉然后还回去了空盘子。而确认迟到可以看作是因为服务员偷懒,等了好半天才把空盘子送回后厨,这时候后厨已经重新上了菜,顾客直接倒掉菜把空盘子送回来,后厨也不管了,把服务生送晚的空盘子丢掉。

通过这种确认和重传机制,就可以在不可靠的传输网络上实现可靠的通信。但是停止等待协议是最基础的情况,不难看出整个过程大多数时间都是在等待,信道的利用率是很低的。
这里补充一下信道利用率的概念,信道利用率一个周期内发送分组所用时间占的比例,具体如下图:
在这里插入图片描述
用发送时间除以总时间,得到的就是信道利用率,不出错情况下停止等待协议的信道利用率已经很低了,如果出现重传,利用率会更低,这种低效率是我们不希望看见的。所以延伸出了流水线传输,即发送方可以连续发送多个分组,不必发完一个就停下来,这种方式大大提高了信道利用率,相对的,传输协议也需要发生相应的修改。
在这里插入图片描述
发送方采用了连续发送,确认也需要发生变化。这种情况下采用的是连续ARQ协议。发送方设置一个发送窗口,通过窗口的移动来控制连续发送的范围,窗口可以向后移动,从而推进分组的发送。接收方采用累计确认的方法,不需要对每个分组都进行确认,而是对按序到达的最后一个分组进行确认,这样就表示到这个分组为止的所有分组都已经收到了。这种方式好处在于即使丢失,也不一定要重传,但是不能够向发送方反映出接收方的所有接收信息。
这种累积确认可能会导致回退N的现象。这种现象主要是因为中间部分的丢失导致的,比如说发送方发送了5个分组,但是第三个分组丢失了,根据累计确认机制,确认的是2号分组,而45号分组的情况发送方是不知道的,此时发送方会重传3-5号分组,造成一定的浪费。所以说当通信线路质量不好时,连续ARQ协议会带来负面影响。
在这里插入图片描述
TCP采用这种机制之后,就需要在发送方和接收方设置发送窗口和接收窗口,这四个窗口的大小是动态变化的,会根据彼此的收发状况调整。当接收方数据处理不过来时,接收窗口变小,通过TCP分组告诉发送方自己快接收不下了,于是发送方就缩小发送窗口,从而减慢发送速度,这就是下面TCP流量控制的核心。这里需要注意,虽然发送窗口是受接收窗口调整的,但是同一时刻二者并不一定一样大,主要还是网络存在延迟,此外还收到拥塞状况的影响,发送方也会根据拥塞状况来调整自己发送窗口的大小。
在这里插入图片描述
采用这种滑动窗口的设计,一个窗口内的分组可以区分为一下四类:
①已经发送且接收方已经确认
②已经发送但是接收方还没有确认
③未发送但接收方允许发送
④未发送且接收方不允许发送
在这里插入图片描述
当收到确认之后,整个窗口就会滑动,让窗口的前沿移动到接收端希望收到的序号上,后沿也向后移动等长距离。这样窗口的位置就可以由窗口前沿和后沿的位置共同确定。后沿有两种可能,一种是在没有收到新的确认的情况下会保持不动,另一种则是前移(接纳新数据)。需要注意后沿是禁止向后移动的,因为不能撤销已经确认的分组。前沿一般是向前移动,当没有收到新的确认时保持不动,此外如果接收方接收窗口变小了,也是有可能让后沿前移而前沿不动的。前沿有可能向后收缩但是TCP强烈不建议,主要还是涉及数据的发送,有可能让已经发送的数据又变为不允许发送的状态。
在这里插入图片描述
至此ARQ协议其实基本已经完全了,接着用后厨顾客服务员的例子来简化一下,这次后厨换了个大号的托盘来让服务员上菜,顾客也换了个大号的桌子用餐,后厨做好的菜先放在厨房台子上,上菜时就把菜放到托盘上让服务员上菜,因为怕菜凉了,所以要根据顾客吃菜的情况来调整做菜速度,顾客也很任性,一定按照顺序吃并且吃完了就把空盘子按照上菜顺序摞起来,如果哪一道菜被服务员偷吃了就等着不往下面吃,服务员收拾空盘子送回后厨,后厨一看最上面的空盘子是哪一道菜的,就知道顾客吃菜吃到哪一道了,并且顾客也会告诉后厨自己桌子上还有多少空地,如果快满了就上慢点,厨师如果看见自己送出去了菜顾客没吃到,就重新上一遍给顾客。这样一个例子就可以大体概括整个ARQ协议的知识了。

发送缓存和发送窗口是一对很容易搞混的概念,发送缓存实际上是要大于发送窗口的,发送缓存用来存放应用程序传送给发送方TCP准备发送的数据以及TCP已经发送出去但是尚未收到确认的数据。而接收缓存存放的则是按序到达但是未被应用程序读取的数据以及不按序到达的数据。如下图:
在这里插入图片描述
在这里插入图片描述
在这个协议中,重传时间的确定也是一个很重要的问题,由于网络的状况是动态变化的,所以重传时间也需要随着网络状况而发生变化。如果设置过大会使得网络空闲时间增大,从而降低了传输效率。如果设置过小,会让很多报文段出现不必要的重传,进而使网络负荷增大。
重传时间主要是根据RTT来判断的,要确定重传时间,主要是要先确定加权平均往返时间RTTS。第一次测量得到的RTT直接作为RTTS,之后按照下面的方法计算:
在这里插入图片描述
超时重传时间RTO应该略大于上面得到的RTTS,一般取RTO=RTTS+4×RTTD,其中RTTD是RTT的偏差的加权平均值,计算方法如下:
在这里插入图片描述
需要注意的是,新的RTTD的计算需要用到RTTS,而这里的RTTS是上一次的数据,也就是说计算顺序应该是RTTD-RTTS-RTO,利用上次测出的RTTS和新测的RTT得到新的RTTD,再利用新的RTT和旧的RTTS得到新的RTTS,最后相加得到RTO。
RTT的计算也是个技术活,在出现重传的情况下这个问题更加复杂,如何确定确认报文是对原来的报文的确认还是对重传的报文的确认是个问题。对于这个问题主要采用KARN算法,该算法在计算RTT时,只要重传了就不让测量出来的数据参与运算,所以得到的RTTS和RTO就会准确很多。但是这种方式会在时延突然增大的情况下出现无法更新的情况,所以又出现了修正KARN算法,如下图:
在这里插入图片描述
对于连续确认,还有一种情况是一大串报文都到达了接收端,但是中间只有一个分组传输失败了,按照ARQ,会出现回退N的现象,而且一旦这个N很大,浪费的代价也会很大,所以又延伸出了选择确认SACK,该协议规定,如果接收方收到了和前面的字节流不连续的两个字节快,如果这些字节的序号都在接收窗口内,就先收下这些数据,然后准确告诉发送端,从而不再重传重复的部分。用后厨顾客服务员的例子,就是顾客写了个纸条放在空盘子上,告诉后厨自己现在上了哪些菜,已经到了顾客桌子上的必然就没有被服务员偷吃,所以不用再做一次。
虽然SACK功能很强大,但是传输的开销有点大,因此作为选项部分,放在TCP首部的选项部分,如果需要,建立TCP连接时就需要提前由通信双方协调好。

5.6 TCP的流量控制

搞明白前面的窗口机制,这一节的流量控制就不是很难。流量控制主要还是靠滑动窗口机制来实现的。流量控制就是让发送方的发送速率不要太快,既要让接收方来得及接收,还要防止网络发生拥塞。
这个过程的实现主要还是利用TCP分组首部的六位来解决,在建立TCP连接时就提前设定好接收方的接收窗口,之后的过程可以看下面的这个模拟图:
在这里插入图片描述
流量控制就是采用这种方式,不断利用确认分组中的rwnd字段来调整发送端的发送窗口大小。但是这种机制也会出现死锁,就是当接收方没有缓存可以接收时,就会发送零窗口报文,从而发送方将发送窗口设置为0,即停止发送,之后等接收端有了足够的内存接收时,又会发送非零窗口大小的报文,正确情况下发送方收到这个报文会继续发送,但是如果这个报文丢失了,那么就会导致互相等待从而死锁。因此TCP为每个连接设置了一个持续计时器,只要一方收到了零窗口通知就启动这个计时器,超过计时就发送一个探测报文,如果接收窗口仍然是0就继续等待,这样就可以避免这种思索情况的出现。

前面提到过TCP是面向字节流的,什么时候打包发出去是TCP的活,要考虑传输效率,所以需要采用一定的机制来控制TCP报文段的发送时间,主要有下面三种机制:
在这里插入图片描述
除了发送大小,什么时候发送也是个问题,现实中一般采用NAGLE算法,如果发送应用进程把要发送的数据逐个字节送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,后面到达的数据字节都缓存起来,收到第一个确认时再把缓存中所有的字节打包发出去。除此之外该算法还规定,当到达的数据已经达到发送窗口的一半或者达到报文段的最大长度时就立即发送。这样子就成功提高了吞吐量。

另一个问题叫做糊涂窗口综合症,这种问题主要是出现在发送端应用进程产生数据很慢或者接收端处理接收缓冲很慢时,此时TCP传输的都是些很短的分组,从而让网络的效率很低。解决方法分两个方向,发送端可以让应用进程攒一攒再送到TCP缓存,即采用NAGLE算法,接收端采用延迟确认ACK,到达后不立即发送确认报文,直到缓存有足够的空间再发送,从而防止了接收端缓存不足的现象。

5.7 TCP的拥塞控制

拥塞控制控制这里很容易和前面的流量控制搞混。所谓拥塞,指的就是某一时间段,对网络中资源的需求大于可用部分,网络的性能就会变坏,即产生拥塞,所以产生拥塞的条件就是对资源需求的总和大于可用资源。
拥塞控制是一个全局性的问题,涉及全网的所有路由器、主机。而流量控制往往是指给定的发送端和接收端之间点对点通信量的控制,是一个点对点的问题。但是某些拥塞控制算法是向发送端发送控制报文,以此告诉发送端网络已经很慢必须慢慢放慢发送速率,这一部分和流量控制是很像的。所以只需要几号这两种控制区别在于范围就可以了。

要想实现拥塞控制,首先需要获得网络内部流量分布的信息,还需要设置交换信息和命令以便结点进行控制,除此之外还需要全局考虑得失。
拥塞控制是一个动态的问题,是一个很难解决的问题,并不能一切按照理想状态去设计。
在这里插入图片描述
拥塞控制主要有两大类:开环控制和闭环控制。
开环控制指的是在设计网络时提前将可能发生拥塞的原因考虑清楚,力求在工作室不产生拥塞。
而闭环控制则是基于反馈,在工作过程中动态监测可能发生的位置、可能在何时发生,从而及时调整。关键在于监测网络的拥塞,一般的指标为:
在这里插入图片描述
重点在于拥塞控制的方法,主要有四种方法:慢开始、拥塞避免、快重传和快恢复,这四种方法的组合形成了TCP的很多个不同版本,也是这本书最复杂的地方,只要过了这一部分,后面就没有更难的知识了。
在介绍这四种方法之前,为了方便建模,假定数据单向传输,而且接收方有足够大的缓存空间,即发送窗口的大小取决于网络的拥塞程度。

发送方需要维持一个拥塞窗口cwnd,这个大小取决于网络的拥塞程度并且在动态变化,变化的原则是只要网络没有出现拥塞,就再增大一点,以便把更多的分组发送出去,但是只要出现拥塞,就减小注入网络的分组数目。

慢开始主要思想是在开始发送数据时,不是立即发送大量数字,而是从小开始,试探着增大。
主机刚开始发送报文时都先设置拥塞窗口大小为1,即设置为一个最大报文段MSS的值,每收到一个对新的报文段的确认之后,就将拥塞窗口加一,这个一也是一个MSS的值,这样逐步增大拥塞窗口的值,从而可以使分组注入网络的速率更加合理。
这里还要引入一个概念叫做传输轮次,一个传输轮次实际上就是往返时间RTT的变形,一个传输轮次强调把拥塞窗口所允许发送的报文段都发送出去并收到最后一个字节的确认所划分的时间,这个时间是大于RTT的,但是和RTT密切相关。
在慢开始中,没经过一个传输轮次,拥塞窗口就加倍,这个加倍是表现上的加倍,实际上是由于一个传输轮次中,每收到一个确认拥塞窗口加一,所以一个传输轮次下来效果上就是翻了一倍,但不要理解成翻倍,而是一点一点加出来的。
在这里插入图片描述
所以我们不难发现,慢开始其实一点也不满,与其说是慢开始,不如说是少开始。慢开始实际上相当于指数倍增,不用多久就会变得很大,所以为了防止拥塞窗口过大,需要设置慢开始门限,当小于这个门限时采用慢开始,而超过就会转为拥塞避免算法。

拥塞避免主要思想是让拥塞窗口缓慢增大,与慢开始指数增长不同,拥塞避免阶段没经过一个RTT才让拥塞窗口加一,所以是按照线性规律缓慢增长,这才是真正的“慢开始”。这一过程也称作加法增大。
无论是在慢开始还是在拥塞控制阶段,只要出现了拥塞,就需要将慢开始门限设置为出现拥塞时拥塞窗口的一半,并把拥塞窗口重新设置为1再从慢开始算法开始。这样做就可以减少发送入网络的分组数,从而让网络中的路由器有时间处理完积压的分组。这一过程也称作乘法减小。
拥塞避免并不能完全避免拥塞,而是说采用这样线性增长的方法,可以让网络不是很容易出现拥塞。

这两个是TCP拥塞控制最基本的环节,这两个环节加上快重传的TCP版本称为TCP Tahao版本,这个版本的TCP由于每次拥塞都会让拥塞窗口从1开始使用慢开始算法,所以会产生很大的网络波动,现在已经被淘汰,但仍然作为最基础的TCP版本。图示如下:
在这里插入图片描述
快重传算法要求接收方每收到一个失序报文段就立即发出重复确认,这样就可以让发送方尽早收到,此外还要求发送方只要一收到三个重复确认就立即重传对方未收到的报文段。这种算法不是取消了超时重传计时器,而是在超时重传计时器到时间之前就先重传,从而让原本可能会判断为超时的分组被补上,这样就不会出现超时,发送方也就不会认为出现了网络拥塞。

快恢复算法则要求发送段在收到三个连续重复的确认时,就执行乘法”乘法减小“,把慢开始门限减半,但是不去执行慢开始算法,从前面快重传算法里也可以看出,三个重复确认并不一定表示网络拥塞,所以快恢复要求继续执行拥塞避免算法,让窗口缓慢增大。

所以快重传和快恢复实际上是配合使用的,在出现三个重复确认时就提前采取行动,这时并不一定是拥塞了,但是存在风险,所以主动出击,马上重传确实报文并调小自己的慢开始门限和拥塞窗口,之后当做没发生一样加法增大。
引入了快恢复的TCP版本称为TCP RENO版本,从下面的图可以看出,此时网络的波动已经没有那么大了,性能也就有所提升。
在这里插入图片描述
对于TCP RENO版本,控制的流程图如下:
在这里插入图片描述
对比这两个版本的TCP,我们可以进行一下对比。
Tahoe版本是早期版本,其核心思想是让拥塞窗口以指数增长方式靠近可用的信道容量,之后慢慢接近,包括慢开始、拥塞避免、快重传三部分,由于不存在快恢复,所以只要收到三个重复确认或者出现超时就会引起网络的激烈震荡,大大降低了网络的利用率。可以这样说一旦掉包,拥塞窗口就会被打回原形,在恢复丢失的包之前窗口值为1,根本不能传新的包,所以吞吐量为0。
Reno版本增加了快恢复,所以完成快重传之后进入了是拥塞避免而不是慢启动,所以避免了网络的剧烈震荡。

这一节剩下的部分算作一个补充吧,也不清楚到底是以哪个为准。百度百科和老师上课的可见对于快恢复的介绍和课本上是不一样的。课本上认为进入进入快恢复之后,慢开始门限设置为一半,拥塞窗口等于减半后的慢开始门限。但是实际上这一个过程中,慢开始门限减半,拥塞窗口变成减半后的慢开始门限加三。这是因为能够收到3个ACK,说明这时候已经有三个分组到达了接收端,所以窗口中完全可以再添加3个分组的位置,简单来说就是网络没有那么差。
之后重传丢失分组,此后没收到一个重复的ACK就让拥塞窗口加一,直到收到对新发送的数据的ACK时,才将拥塞窗口设置为减半后的慢开始门限并进入拥塞控制阶段。这一步中又增加了拥塞窗口,是因为重复的ACK之所以出现,是因为发送的其他分组比重传分组更早到达接收端,相当于此时网络中又空出来了一个位置,充分利用资源所以加一。这里还需要说明,虽然我们不断扩大拥塞窗口,但是实际可以同时发送的报文个数仍然是减半后的拥塞窗口的个数个,仔细想一下,增大的目的实际上就是为了把窗口的前沿向前移,后沿被卡在重传分组那里,又回来一个旧的ACK,说明此时这个窗口里有一个到了接收端,加一之后就可以发送后面新的了。收到新的ACK表明重传完成了,所以就卡住的后沿就解放了,就可以恢复正常了。
这一部分算是快恢复的补充,实际上是快恢复算法的具体实现步骤,课本上没有提,要是这么想的话课本也没错,因为课本说的是快恢复之后进入拥塞控制,门限值减半并将窗口值设置为减半后的门限值。人家也没说在快恢复部分怎么实现。仅作为补充即可,408都不这么考。
在这里插入图片描述
当然TCP Reno版本也存在缺点,当出现多个连续丢包时,多次进入快恢复和快重传,慢开始门限值是一直在减小的,多次丢包会让门限值和窗口值变成1,而且快恢复之后采用的是拥塞避免算法,是一点一点增加的,所以在减小到1之后,不能像慢开始那样快速回到巅峰速度,即恢复慢。针对这一问题,又出现了NewReno版本,这个版本当只有一个包丢失时和一般的Reno是一样的,只有在出现多个丢包时才有区别,NewReno会持续重传三个ACK之后的数据包,直到所有丢失的数据包都传送成功后才会结束快恢复进入拥塞避免,从而减少了大量数据包丢失对Reno造成的影响。

SACK是Tcp Reno延伸出的另一个版本,主要是可以在一个RTT时间内重传一个以上的数据包。当一个窗口出现多个丢包时,SACK和NewReno都可以快速平稳地恢复过来,而Reno则会经常超时然后慢启动,严重影响性能。这两个版本也作为补充。

上述的拥塞避免算法并没有与网络层联系起来,实际上网络层的策略对拥塞避免算法影响最大的是路由器的丢弃策略。简单来说就是当传播过程中的路由器满了的时候,应该采用什么样的策略来丢弃后来的数据。
简单的情况下是按照先进先出的方法来处理,缓存装不下就丢弃,这叫做尾部丢弃策略,这样会导致分组丢失,从而让发送方认为网络产生拥塞。更为严重的是网络中存在着很多条TCP连接,他们一般是复用路由路径,这一丢失,就可能影响很多条TCP连接,结果就是许多TCP连接在同一时间进入慢开始状态,这称为全局同步。全局同步会让通信量突然下降很多,恢复正常之后又增大很多。
解决方法是用随即早期检测RED,通过将路由器的到达队列划分为三部分,提前采取措施,不等出现丢弃就提前开始控制,具体操作如下:
在这里插入图片描述
这里需要注意,整个一节提到的发送窗口,都是在接收端完全可以接收的前提下,整个网络只受拥塞情况的限制,此时发送窗口就等于拥塞窗口,但是把假设的前提去掉,发送窗口实际上是受到拥塞窗口和接收窗口双重限制的,其值取二者中更小的那一个。

5.8 TCP的运输连接管理

最难的部分已经过去,这一节主要是TCP连接的建立以及释放的过程,并不难,主要还是理解好前面首部的六位。

建立连接的过程主要任务还是让双方都可以感知到对方的存在,并且协调好双方的一些参数和资源。
TCP的连接建立简称为三次握手。第一次握手,客户端的TCP向服务器发送连接请求报文段,利用首部中的SYN位,并且由客户端系统提前设定好一个序号假设为x,写入首部的seq字段。第二次握手,此时仍然处于配置状态,所以服务器发给客户端的报文中SYN仍要设置为1,此时服务器要对客户端进行确认,所以要让ACK=1,并且写入要鉴别的序号由于TCP规定SYN报文不携带数据但是消耗一个序号,所以确认号应该填上x+1,同时服务器系统也要自己设定一个开始序号填入,假设为y,发回到客户端后再进行第三次握手,这时双方已经协调完毕,不需要再使用SYN,只需要协调好序号和确认号,TCP规定服务器发回的第二次握手不能携带数据,但是也要消耗一个帐号,所以确认号为y+1,序号为x+1,于是可以得到下面的三次握手示意图:
在这里插入图片描述
准确来说,即使是无数次握手也不能保证百分百成功建立连接,只要最后一次确认丢失,双方就处在一个信息不对等的状态,而采用三次握手主要是因为互相都知道对方准备好传输数据至少需要三次,只要三次成功,就可以说有相当的概率可以正常通信了。

TCP连接的释放则是四次握手,传输结束之后,通信双方都可以释放连接,一方先发送释放连接报文段,使用的是首部中的FIN位,将其设置为1表示想要断开连接,另一方接收后给出回应并给出确认。此时整个TCP链接实际上是处在一个半关闭的状态,一方已经不能发送了,但是另一方是可以继续发送的,如果此时另一方也传完数据了,就将剩下的一半TCP连接也断开。这一半连接的断开与前面基本一样,区别在于先断开的一方要等待2MSL时间,即两倍的最长报文段寿命。这样做的目的是保证发送的最后一个ACK能够正确到达对方,同时也是防止已经失效的连接请求报文再次出现在连接中。经过2MSL时间指挥,所有产生的报文段就都在网络上消失,也就不会出现上面的问题。
在这里插入图片描述
上面这个图就是释放连接时的四次握手,可以看出双方实际上是各自进行了两次握手来实现了释放,这里的考点主要是在于序号的确定上,搞清楚序号之间的关系,TCP的连接和断开并不是什么难题。

为了防止TCP之间的连接出现长时期的空闲,还设置了保活计时器,一定时间内没有响应就会断开连接以防资源的浪费。

典型题

在这里插入图片描述
这两道题属于这一部分很典型的题目,题目本身考的是TCP拥塞控制的过程,只要按照算法慢慢写就可以写出来,关键在于题目的时间点。对于21题,叙述的时间点是报文段得到确认之后,所以是第四次发送完成,根据慢开始算法的过程,窗口变化应该为1-2-4-8-16,第四次完成数间隔号,所以拥塞窗口大小为16KB,C项正确。同样的道理处理第22题,这道题也是先找好时间点,第13次传输,就是说12次完成,所以看第13个数,过程为:1-2-4-8-9-10-11-12-1-2-4-6-7-8,可见窗口为7,C项正确。
在这里插入图片描述
在这里插入图片描述
这道408的考题就很综合,把运输层、网络层、数据链路层全部联系在了一起,题目本身不难,但是在于综合性,关键在于理解好表一的内容,表一实际上是TCP连接中的报文的十六进制表示,对于一个表项,第一行是IP分组的首部,第二行是TCP报文的首部,对应着后面给出的首部结构来看就好。第一题就是看表,通过IP首部中的源地址,找出编号1 3 4的分组为H发送。之后哪几个完成了TCP连接建立过程,这个问法有点奇怪,题目的意思是哪几个可以代表TCP连接的建立过程,即三次握手,而这个表达方式很容易让人误认为是问那些分组已经连接建立完成,所以要看TCP首部的6位,找出对应三次握手特征的三个分组,即编号1 2 3的分组。之后又问那些进行了填充,这里就要明白为什么要进行填充,是因为以太网的最短帧长限制,少于64B的就会认为是无效帧,所以这里就需要利用IP分组中的总长度,判断是否小于最短帧长,3 5号分组数据部分长度为40B,需要填充。
第二问利用序号和确认号直接算就好,让确认号减去序号得到16B。
第三问看IP首部中的TTL字段,直接减就好,结果为15个路由器。
在这里插入图片描述
数据帧的长度是不确定的,这种情况要选择最短情况,因为如果按照最大帧长计算,当帧长为最小帧长时信道达不到最大利用率。发送一帧的时间为128×8/(16×1000)=64ms,所以发送一帧到收到确认的时间为64+270×2+64=668ms,这段时间可以发送668/64=10.4帧,而为了保证序号不重复,需要让编号数目大于10.4帧,于是要用4位比特进行编号,这样子可以编号出16个编号,B项正确。
在这里插入图片描述
这道题主要是序号和窗口大小的考察,第一问没什么好说的,连续确认直接得到C项。第二问帧的序号长度为k比特时,对于选择重传协议,为了避免接收端向前移动窗口后新旧窗口产生重叠(防止序号重复),接收窗口的最大尺寸不应该超过序列号范围的一半,即D项正确。第三问设发送窗口序号为L-U,发送窗口初始大小为W,所以又0<=U-L+1<=W因此L》=(U-W+1)mod2^k。
在这里插入图片描述
甲的窗口大小为1000,所以在收到第一个确认之前最多可以发送1000个1000B的分组,即发送1MB的数据,而一个周期的时间为发送时间加上RTT,即1000B/(100Mb/s)+50ms+50ms=0.10008s,此时最大传输率为1MB/0.10008s=80Mb/s,C项正确。
在这里插入图片描述
这两道题属于同一个类型,十五题首先计算发送周期,发送周期对于这道题只有发送帧的发送时延和RTT,所以T=1000B/128kb/s+250ms×2=0.5625s,题目要求利用率不小于80%,所以假设数据大小为L字节,则有等式:(L/128kb/s)/T>=0.8,即L>=7200B,所以一个周期内至少要发送7.2个帧,所以需要的序号至少为4个才可以,B项正确。十六题信道利用率等于传输帧的有效时间除以传输周期,设帧长度为x比特,则有效时间为x/(3kb/s),而传输时间为发送时延加上RTT,即x/(3kb/s)+400ms,计算可得x=800bit,D项正确。

猜你喜欢

转载自blog.csdn.net/weixin_43849505/article/details/113642428