网络-----TCP的可靠性保证相关机制

在之前,我们已经初步接触了TCP协议

TCP是传输层的协议它的主要特点有:

  • TCP是面向连接的(TCP的三次握手和四次挥手)
  • TCP面向字节流
  • TCP带缓冲的(不会立即发送,会等到一个合适的时机再发,因为有可能来不及应答)
  • TCP是全双工的
  • TCP保证了可靠传输
  • TCP具有流量控制

今天我们主要谈一下TCP是如何保证可靠性的


确认应答机制

TCP的确认应答机制就是,发送端给接收端发送的数据,当接收端收到之后会返回一个确认消息,这个确认消息也就是确认应答ACK

TCP的确认应答机制是基于序列号实现的,这个序列号也就是我们TCP报头中的序号和确认序号。TCP的报文到达确认,是对接收到的数据的最高序列号的确认,并向发送端返回一个下次接收时期望的TCP数据包的序列号。例如,主机A发送的当前数据序号是1,数据长度是400,则接收端收到后会返回一个确认号是401的确认号给主机A,表示下次想从401开始接收数据。
上一张图:
网络-----TCP的可靠性保证相关机制_第1张图片

可以看出来,TCP通过这种确认应答机制来判断接收端是否收到发送端发出的数据。
可是如果发生数据包丢失,或者确认应答丢失的情况怎么办呢?
超时重传机制就可以解决这个问题


超时重传机制

超时重传机制指定是,发送的数据包在没有收到相应的ACK,等待一段时间,超时之后就会认为这个数据包丢失了,就会重新发送。
网络-----TCP的可靠性保证相关机制_第2张图片

如图所示主机B由于网络或其他原因没有收到主机A发送的数据(也可能是主机B收到数据后检测到该数据包有差错而丢弃),主机A只要超过了一段时间仍然没有收到主机B的确认应答就会认为刚才发送的报文丢失了,因而重传该报文。

再想想,如果是主机B的确认报文丢失了呢?
网络-----TCP的可靠性保证相关机制_第3张图片
同样的,主机A没有收到主机B的确认就会重发刚刚发送的数据,那么主机B不就会有重复数据了吗?我们利用刚刚谈过确认应答机制中序号就很容易做到去除重复包

TCP在实现超时重传时要注意以下几点:

  • 主机A在发送完一个报文后,必须暂时保留已发送分组的副本,只有在收到相应的确认之后才能清除
  • 报文和确认报文都要进行编号,这样才能明确哪一个是发送出去的,哪一个还没有收到确认
  • 超时重传的时间应当比数据在传输的平均往返时间要长

这个超时重传时间的选择是一个比较复杂的问题,如果设置的过短,就会引起很多报文段不必要的重传使网络负载增大;如果设置的过长又会使网络空闲的时间增大,降低了传输效率。
TCP采用了一种自适应算法,它记录了一个报文段发出的时间,以及收到相应的确认时间,这两个时间之差就是报文段的往返时间RTT,根据这个RTT在动态计算这个最大超时时间。Linux中超时以500ms为一个单位进行控制,每次判定超时重发的超时时间都是500ms的整数倍


滑动窗口

刚刚说到的确认应答机制,对每一个发送的数据段都要给一个确认报文,收到ACK之后再发送下一个数据段,可以发现这样的效率比较低
来优化一下效率低的缺点,比如我让发送的每一个包都有一个序号,接收端必须对每一个包进行确认,这样主机A一次多发送几个片段,而不必等候ACK,同时接收端也要告知它能够收多少,这样发送端发起来也有个限制,当然还需要保证顺序性,不要乱序,对于乱序的状况,我们可以允许等待一定情况下的乱序,比如说先缓存提前到的数据,然后去等待需要的数据,如果一定时间没来就丢弃掉,来保证顺序性

滑动窗口就可以解决这个问题,来看看滑动窗口的数据是怎么分类的:
网络-----TCP的可靠性保证相关机制_第4张图片
1. 已发送成功且受到确认的数据:例如图中的前29个Bytes,这些数据的位置其实已经在窗口之外了,因为当窗口内最小的序号被确认之后窗口就要向前移动
2. 已经发送但还没有收到确认的数据: 数据已经被发送出去了,但是还没有收到接收端的确认,发送端就认为并没有完成发送这些数据就还保留在窗口内。(也是为了可能需要重传做准备)
3. 允许发送但还没有发送的数据:这部分数据已经被加载到缓存中也就是窗口中了,这就说明这些数据还是可以被接收方接受的,所以发送方需要尽快的发送这些数据
4. 没有发送也不允许的数据:这些数据是发送端没有发送同时接收端也没有能力接收的数据。

上面我们说的窗口其实是发送端的发送窗口,同样的接收端也会有自己的接受窗口。类似于发送端,接收端的数据有3个分类。因为接收端并不需要等待ACK,所以它没有接收并确认了的分类
网络-----TCP的可靠性保证相关机制_第5张图片
1. 已经发送确认并交付主机数据:如图中,在接受窗口外面,到29号为止的数据都是已经发送过确认并交付给主机了,因此在接受窗口中就不用再保留这些数据了。
2. 允许接受的数据:接受窗口中的内的序号(30~40)是允许接收的。在图中主机B收到了31和32的数据,这些数据没有按序到达,因为30号数据没有收到(可能丢失也可能滞留在网络中),所以主机B发送的确认报文只能是31。
3. 不允许接受的数据:这些数据是接收端不允许接收的,只能等待窗口中有数据确认窗口前移才会被允许接受。

滑动窗口的原理

继续上图来解释原理:

网络-----TCP的可靠性保证相关机制_第6张图片
如上图所示,假设发送窗口的大小为20字节,其中30号字节之前数据都是已经发送而且受到了接收端确认的数据了。再来看看窗口中的数据,窗口中的数据可以被分为两部分,一部分表示已经发送出去但是还没有收到确认的数据,另一部分表示还没有发送但是允许发送的数据。最后一部分就是在窗口之外,表示不允许发送的数据。
与发送窗口对应的就是接受窗口了,同样的30号字节之前的数据都是已经发送确认并交付给上层应用的数据,而接受窗口中就保存着可以接受的数据,接受窗口外面就是不允许接受的数据。

来看看传送数据之后的变化:
网络-----TCP的可靠性保证相关机制_第7张图片
发送端收到了接收端对30~34号字节发送的确认,这时发送窗口就会向前移动,产生一些新的空位,这些空位容纳的就是允许发送的数据

来总结一下滑动窗口工作的原理:

  • 假设30~44 这些数据,是上层应用发送给TCP的,TCP将其分成四个数据段来发送
  • seg1:30~32;seg2:33~34;seg3:35~40;seg4:41~44;这四个片段,依次发送出去,此时假设接收端之接收到了seg1、seg2和seg4
  • 此时接收端的就回复一个ACK包说明已经接收到了30~34的数据,并将seg4进行缓存,因为seg4没有按序到达
  • 发送端收到ACK之后,就会将30~34的数据包从发送但没有确认移动到发送并已经确认,这个时候窗口向右移动
  • 假设接收端的窗口大小没有发生变化,此时窗口右移,产生一些新的空位,这些是接收端允许发送的范畴
  • 对于丢失的seg3,如果超过一定时间,TCP就会进行超时重传,重传成功seg3和seg4就一块被确认,不成功,seg4也将被丢弃

滑动窗口得到原理就是不断重复上述过程,随着窗口不断滑动,将整个数据流发送到接收端,实际上接收端的窗口大小也是会变化的,接收端会根据这个值来确定何时应该发送多少数据


流量控制

先来说说什么是流量控制:流量控制就是让发送端发送数据的速度不要过快,要让接受端来的及接收,因为接收端处理数据的速度是有限的,如果发送端发送的过快,导致接收端的缓冲区被打满,这个时候发送端要是继续发送数据就会出现数据报丢包的问题,继而引起重传等一系列机制。所以TCP有了流量控制,来决定发送端发送数据的速度
TCP是利用大小可变的滑动窗口来实现的,在最开始建立连接的时候,发送端和接收端会通过TCP首部窗口大小字段来协商发送窗口的大小,但在通信过程中,接收端也可以根据自己的情况来动态调整对方发送窗口的最大值。
来看个例子吧:
假设最开始,B告诉A自己的接受窗口rwnd=400,所以发送方的发送窗口不能超过接收方给出的接收窗口的数值。再设每一个报文段的大小是100字节的,而报文段初始序号为1。
网络-----TCP的可靠性保证相关机制_第8张图片
从图中可以看到,主机B一共进行了3次流量控制。第一次将接收窗口rwnd减小到300,第二次减小到100,最后一次减小到0。也就是不允许主机A发送数据了。这种状态将持续到主机B重新发过来一个新的窗口值为止。
再来假设一种场景,主机B接收缓存中的数据已经被取走,所以主机B向主机A发送了rwnd=400的报文段,可是这个报文段再发送过程中丢失了。A一直等待B发送窗口大小,而B也一直等待A发送数据,如果没人来打破这个僵局,那就一直是互相等待的死锁局面了。
为了解决这个问题,TCP为每一个连接设有一个持续计时器。只要TCP连接的一方收到对方的零窗口通知就启动这个计时器。如果计时器设置的时间到了还没有收到对方的接收窗口,就给对方发送一个零窗口探测报文段,这个报文段仅携带一字节的数据,而对方收到这个探测报文段就会给出自己现在的窗口值。


拥塞控制

在网络实际的传输过程中,会出现这样的现象。当前的网络上充斥的大量的数据包,却不能被按时送达,已经产生了拥塞的情况,这时候如果还发送大量的数据无疑是雪上加霜。所以TCP就有了拥塞控制,通过拥塞控制来缓解网络的压力。
拥塞控制主要有四个算法:

  • 慢启动
  • 拥塞避免
  • 拥塞控制时,快重传
  • 快恢复

先来看看慢启动和拥塞避免:
网络-----TCP的可靠性保证相关机制_第9张图片
慢启动算法的思想:在刚刚开始发送报文段的时候,先把拥塞窗口cwnd设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值。
在图中。一开始将拥塞窗口cwnd的初始值设为1,表明可以传一个MSS的数据。以后发送方每收到一个对新报文段的确认ACK,就将拥塞窗口值加1,然后开始下一轮的传输。当过了一个往返时间RTT cwnd=cwnd*2,因此拥塞窗口cwnd随着传输轮次按指数规律增长。当拥塞窗口cwnd增长到慢启动的门限值ssthresh时,就改为执行拥塞避免算法。
拥塞避免算法的思想:让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样,拥塞窗口cwnd按线性规律规律缓慢增长。
就像图中到达门限值之后,cwnd每经过一个RTT就加一,按照线性规律增长。
假设到cwnd达24的时候网络出现拥塞,更新后的ssthresh值为12,拥塞窗口再重新设置为1,并执行慢启动算法。当cwnd=ssthresh=12时,该执行拥塞避免算法。

还有两个拥塞控制算法就是快重传和快恢复
快重传:首先,快重传算法要求接收方每收到一个失序的报文段后就立刻发出重复确认,而不要等待自己发数据时才进行捎带确认。并且快重传算法规定:发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必等待设置的重传计时器到期。
与快重传配合的就是快恢复算法了。
快恢复算法的过程中有两个要点:

  • 当发送方收到三个重复确认时,就执行”乘法减小”算法,把慢启动门限值ssthresh减半。
  • 由于发送方会认为现在网络没有拥堵,因此现在不执行慢启动算法,而是把cwnd值设置为慢启动门限ssthresh减半之后的数值,然后开始执行拥塞避免算法。

你可能感兴趣的:(理论知识,网络)