TCP协议------可靠性保证机制

        在这篇博客中介绍了连接管理机制,它是TCP协议保证可靠性的重要机制,除了该机制,还有许多实现可靠性得机制,本文中将一一进行介绍。

1. 确认应答(ACK)机制

        在TCP的协议报头中有两个字段:序列号和确认序列号。这两个字段就是来保证确认应答机制的。

        发送方A将要发送的多个数据段排好序发送给接收端B。比如说A要发送序列号为1~1000的数据段。B如果将这些数据全部正确接收了,就会给A发送一个1001的确认序列号,用于告诉A,它之前发送的1~1000已经被正确接收,下次从1001开始发送。如果B只接受到了1~500,此时就会给B发送501的确认序列号,A收到后会知道500~1000的报文丢失,就会重新发送500~1000的报文段给B。此时就保证了数据的可靠传输。

        因为TCP协议是全双工通信,双方都可以作为发送方和接收方,因此每一方都需要一个序列号和确认序列号来保证数据的可靠传输。

        设置序列号同时也可以保证发送的数据按序到达,如果多个数据段在发送过程中可能到达的先后顺序可能不同,因此可能会导致接受到的数据与发送时的顺序不一致,通过序列号可以保证数据按序到达,也能够保证数据的可靠性传输。

        如果接收端接收到重复的数据段后,也可以通过序列号来进行去重,保证可靠性。

        综上,序列号和确认序列号的作用有以下几点:

(1)保证确认应答机制;

(2)保证数据按序到达;

(3)保证去重机制。

2. 超时重传机制

        当主机A向主机B发送数据报后,一段时间内A没有收到B的确认信号,就会进行重传。造成重传的原因有两个:

(1)A向B发送的数据在传输过程中丢失,那么A再次重传数据时,就可以保证数据可靠送达;

(2)如果B接收到A的数据了,但B发给A的ACK确认信号在传输过程中丢包了,此时,A再次重传时,B就会接收到重复的数据,此时B就可以根据报文中的序列号进行去重,保证数据的可靠性传输。

        超时重传的时间如何设定呢?

        如果时间设置的太长,当数据报丢失时,就会影响重传的效率;如果时间设置的太短,当ACK包延迟时,就会重传大量的数据包。所以这个时间最好是能保证ACK一定能到达的最短时间。

        TCP协议通过动态计算这个超时重传的时间。

        在Linux中,超时重传的时间间隔是500ms的2^n倍(n = 0,1,...)。如果第一次发送数据报之后,500ms内没有收到ACK确认,则进行重传;然后在2*500ms内没有收到ACK确认,再次进行重传;再等4*500ms,还没收到确认,再次进行重传;...当重传的次数超过一定的上限后,TCP会认为此时的网络或对方的连接出现异常,会强制关闭连接。

        因此,在进行数据传输时,主机A在发送完数据报之后,会先设置一个闹钟,如果在闹钟没响之前ACK报达到,此时取消闹钟,进行后续的数据传输;如果闹钟超时了,ACK报还未到达,此时A就会重传数据,并重新设定闹钟为新的值。

3. 流量控制

        如果发送端发送数据的速度过快,导致接收端的接受缓冲区被占满了。此时,发送端在发送数据时,接收端就不能接收,从而造成丢包,然后发送端会再次重传,造成资源等浪费问题。

        在TCP协议的报头中有一字段“窗口大小”,它就是接收端用来填写自己可接收缓冲区的大小的。在客户端和服务器端建立三次握手期间会在向对方发送的ACK报文中填写自己的可接收缓冲区大小。当双方开始通信后,发送端A向接收端B发送完数据之后,B会向A发送ACK确认报,此时可以将B的新的窗口大小放置在ACK包中告诉A自己的接收能力。同理,A也可通过该方法告诉自己的接收能力(窗口大小)。

        所以,接收端可以将自己的接收缓冲区还能接收多少数据的大小(窗口大小)告诉发送端,发送端根据这个值来控制自己发送的速度,如果窗口比较小时,就减缓发送的速度。如果接收端的可接受缓冲区大小为0,此时,发送端就停止发送数据。当接收端的窗口大小不为0时,要向发送端发送一个窗口更新的通知,使发送端再次开始发送数据。如果一段时间(超时重发的时间)后,发送端还没有收到接收端窗口更新的通知,就会向接收端发送一个窗口探测的数据报(该报文中的PSH标志位为1),然后,接收端会将此时自己的窗口大小告诉发送端。如果窗口更新的报文丢失,发送端就会一直发送窗口探测的数据报。

        在上述中,TCP通过接收端的接收能力来控制发送端的发送速度,就叫做流量控制。窗口越大,网络的吞吐量越高。

        在TCP报头中的窗口大小占16位,可以表示的最大数字是2^16即65535,它以字节为单位,所以窗口大小最大为64KB,也就是说接收缓冲区的大小最大为64KB,但是实际的可接收缓冲区大小不能这么小。因此在TCP报头的40字节选项中还有一窗口扩大因子M,所以窗口的实际大小为窗口字段的值左移M位。

4. 滑动窗口

        在确认应答机制中,如果发送端A向接收端B发送一个数据报后,在等待B的应答之后再发送下一个数据报。如果双方数据传输的时间过长,A等待的时间就过长,此时数据的传输效率就会变低。如果A先发送一个数据段1之后,在等待数据段1的时间里继续发送数据段2,在等待数据段1的同时也在等待数据段2的应答,数据段3等,此时就会将各数据段的等待时间重叠起来,这样便可以提高数据传输的效率。

        但是,A一次发送多少个数据段呢?由上述的窗口大小可以知道接收端的接收能力,所以可以发送接收端的窗口大小的数据段。比如,B的窗口大小是4000,一个数据段的大小是1000,因此A可以一次发送四个数据段(1,2,3,4),当收到数据段1的应答之后,滑动窗口后移,A再发送数据段5。依次往后。

        操作系统为了维护这个滑动窗口,在发送端开辟了一个发送缓冲区。将待发送的数据放在发送缓冲区中,如果滑动窗口中的数据表示已发送但是还没收到应答的数据,当收到一个数据段的应答后,将该数据段从发送缓冲区中删除,然后滑动窗口后移,发送新的数据段。

5. 快速重传机制

        如果上述中多个数据段1:0~1000;2:1001~2000;3:2001~3000;4:3001~4000,由A同时发送给B时,会出现以下两种丢包情况:

(1)应答数据段ACK丢包了。如果数据段1的应答ACK丢失了,但数据段2,3,4的应答ACK没有丢失,因为数据段4的应答ACK中的确认序号为4001,表明B将数据段1,2,3,4都已经接收到了,此时就可以忽略数据段1的应答ACK丢失问题了。如果数据段4的确认ACK丢失了,并且后面没有发送更大序列号的报文段,此时就会启动超时重传机制,重发数据段4。如果数据段1,2,3,4的应答ACK都丢失了,此时也会启动超时重传机制,进行重新发送。

(2)数据段丢包了。比如数据段1丢包了,但是2,3,4没有丢,所以B在对A数据段2,3,4的确认报中都会使确认序号置为0。表明B要求重发数据段1,当B接收到A重发后的数据段1后,会将确认序号置为4001,因为4001之前的数据段B都收到了并将它们放到了接收缓冲区中。

        在上述数据段1丢包时,如果A连续三次收到确认序号为0的ACK应答,此时就会将数据段1进行重传。而此时可能还没有到达数据段1的超时重传时间。这种机制就被称为“快速重传机制”(快重传)

        超时重传机制是基本的保证,快重传机制是基于其之上的。当所有的数据报都丢失之后或所有的ACK应答报都丢失之后,就会启动超时重传机制。

        综上所述,我们可以知道TCP协议报头中的窗口有以下作用:

(1)可以指示滑动窗口大小

(2)可以控制发送端的发送速度。

6. 拥塞控制

        如果TCP的刚启动时就发送大量数据到网络中,此时并不知道网络的拥塞状态如何。如果此时网络特别拥塞就会造成大量的丢包问题。因此TCP采用“慢启动”机制。即刚开始发送少量的数据到网络中,如果网络状态良好,再增大发送数据的速度。那么,慢启动时要发送多少数据到网络中,之后又要发送多少数据呢?这里引入拥塞窗口的概念。

        发送方要维持一个拥塞窗口的变量。拥塞窗口的大小根据网络的拥塞状况在动态的变化。发送方使自己的发送窗口大小等于拥塞窗口的大小与接收端接收窗口的较小值。即此时既要考虑网络的拥塞状况,又要考虑对方的接收能力大小。如果没有出现网络拥塞,拥塞窗口就大一点,如果出现了网络拥塞,拥塞窗口就减小。

        慢启动机制为:

最初设置拥塞窗口为1,当接收到一个ACK应答之后,拥塞窗口加1。根据拥塞窗口和接收方的接收能力来决定发送数据的多少。

虽然最初拥塞窗口大小为1,但是因为它是呈指数增长的,之后会越来越大(此时为慢启动算法)。因此发送到网络中的数据会越来越多,造成网络拥塞的概率也会越来越大。

所以,不能使拥塞窗口无限制的增长下去。因此,这里引入一个慢启动的阈值(当TCP启动时,慢启动阈值等于窗口最大值),当拥塞窗口到达这个阈值时,就使拥塞窗口呈线性增长,一次加1(此时为避免拥塞算法)。

无论在慢启动阶段还是在避免拥塞阶段,当引起网络拥塞时,慢启动阈值减小为发生网络拥塞时拥塞窗口的一半,同时拥塞窗口减小为1,再从1开始慢启动增长。(当发生少量的丢包时,我们仅仅触发超时重传机制,当发生大量的丢包时,就认为发生了网络拥塞,此时就要改变慢启动阈值和拥塞窗口了)。

        如下图所示:


        拥塞控制,是发送方使自己的发送窗口大小等于拥塞窗口与接收端接收窗口的较小值。即此时既要考虑网络的拥塞状况,又要考虑对方的接收能力大小。

7. 延迟应答

        如果接收端B的窗口大小是1M,此时发送端A向B发送了500K的数据,如果B接收到数据之后立即发出响应,此时ACK报文中的窗口大小即为500K。

        如果B处理数据的速度很快比如在很短的时间内就将500K的数据处理完了。并且B的处理能力还未到达上限,即给B更多的数据B也能很快处理完。此时,B可以延迟一会,等500K的数据处理完之后,在进行应答,此时ACK报文中的窗口值即为1M。这样A下一次就可以发送更多数据交给B处理。从而提高效率。

        因为窗口越大,网络的吞吐量越大,数据的传输效率就越高。所以要在网络不拥塞的情况下尽可能的提高传输效率。

        但是,也不能一直延迟下去,这里有两个限制:

(1)数量限制:每个N个包就应答一次(N一般为2);

(2)时间限制:超过最大延迟时间就应答一次(最大延迟时间一般为200ms)。

8. 捎带应答

        当主机A给主机B传输数据后,B会向A发出ACK响应报文,之后B可能还会向A发送数据报文,此时,可以将B要给A发送的数据信息搭载在ACK报文上,一起发送给A,这样就可以减少一次的报文发送,从而提高了效率。

        综上所述,TCP协议既要保证可靠性传输,又要提高性能。所以它比较复杂。

可靠性保证为:

    校验和,序列号,连接管理机制,确认应答机制,超时重传机制,流量控制,拥塞控制

提高性能的机制:

    滑动窗口,快重传机制,延迟应答机制,捎带应答机制。


9. 粘包问题

        当数据传输到TCP传输层时,可以根据序列号将数据按序排放在接收缓冲中。当应用层从缓冲区中读取数据时,应用层看到的是一串串的字节流。那么从哪一部分开始,到哪一部分结束是一个完整的应用层数据包呢?如果相对于完整的数据包,应用层在多读或少读数据后就会形成粘包问题。(此时的包是应用层的数据包)

        因此,在应用层读取数据时,要明确两个包之间的界限。

(1)对应定长的数据报,应用层双发可以提前协商好。比如发送端发送数据时一个包的长度为int大小,接收端在接收时也接受一个int大小的数据报;

(2)对于变长的数据报。可以在数据报的头部加上一个数据包长的字段,应用层在读取时可以根据该字段来判断数据报的长度;

(3)对于变长的数据报。还可以在一个数据报的结尾加上一个分隔字符来区分如HTTP协议中的\n,这是由应用层协议来制定的。

        对于UDP来说,如果数据没有交付到上层,UDP协议报头中的数据报长还存在,因此可以根据该字段来读取一个报文的长度。同时UDP是一个一个报文交付到上层的,本身就有明确的边界,而应用层在接收UDP报文时要么完整的收,要么不收,因此不会出现粘包问题。

10. TCP的异常情况

进程终止:进程终止时会关闭文件描述符,仍然可以发FIN,和正常终止没有区别;

机器重启:和进程终止情况相同;

机器断电或网线断开:A,B两端建立连接后,B端因为断电导致连接断开,此时A端并不知道B端的连接已经断开。当它向B端进行写入操作时,发现B端的连接已不存在,所以会发送RST重新建立连接;即使A端没有进行写入操作,TCP也内置了一个保活定时器,定期检查对端的连接状态,一旦对端的而连接不在,本端的连接也会断开。




        



















猜你喜欢

转载自blog.csdn.net/sandmm112/article/details/80496408