保证TCP可靠传输的机制

一.TCP的超时重传与RTT估计

在TCP两端交互过程中,包含数据、确认的报文段有可能丢失,在发送端引入超时重传机制可以很好地解决报文丢失的问题。发送端为每个发送出去的报文设置一个超时定时器,当定时器溢出而报文的确认还没有返回,它就重传该报文段,超时间隔和重传的方式是提高TCP性能的关键,这些都与往返时间估计密切相关。往返时间(RTT)代表了某字节数据发出到对应确认返回其间的时间间隔,TCP会根据往返时间的估计值动态设置各个报文段的超时间隔

二.慢起动与拥塞避免

1、若发送方一开始便可以向网络发送多个报文段,直到填满接收方通告的窗口空间。当发送方和接收方处于同一个局域网时,这种方式可以工作得很好,但是如果在发送方和接收方之间存在多个路由器或速率较慢的链路时,就有可能产生一些问题。在网络中,路由器负责缓存和转发来自于众多主机的数据报,由于路由器的存储能力、转发能力各不相同,主机的数量和数据报流量也会动态变化,所以网络中会出现拥塞的现象。当拥塞发生时,路由器会直接丢弃掉来不及处理的数据报。对于TCP报文段的发送方而言,拥塞仅仅表现为时延的增加(超时),它并不知道拥塞发生在哪里以及发生拥塞的原因。很多TCP协议的实现对时延增加的处理方式就是重传报文段,而这种处理方式只会使更多的数据发送到路由器上,这不可避免地出现了一种恶性循环,最终导致网络的崩溃

2、要解决这种问题,就要使用慢启动(slow start)算法,TCP发送方必须主动减少报文段的发送速率。慢启动算法规定新分组进入网络的速率应该与另一端返回确认的速率相同。慢启动为发送方的TCP增加了另一个窗口:阻塞窗口(congestion window),记为cwnd。当与网络的另一台主机建立TCP连接时,阻塞窗口被初始化为1个报文段大小,发送方取阻塞窗口与通告窗口两者中的最小值作为发送上限。每收到一个ACK,阻塞窗口增加一个报文段大小。在没有拥塞的连接上,稳定状态下的阻塞窗口和发送窗口一样大,而当拥塞发生时,阻塞窗口会减小,从而减少TCP发送的流量。阻塞窗口是发送方使用的流量控制,而窗口通告则是接收方使用的流量控制。当拥塞发生时,我们希望降低分组进入网络的传输速率,发送方通过慢启动与拥塞避免算法主动调节分组进入网络的速率,同时发送方也通过接收方通告的窗口大小来被动调节分组发送速率

3、说到慢启动,就不得不说另一个与拥塞避免相关的算法乘法减小(multiplicative decrease),在实际中这两个算法通常是绑定在一起的,实现也很简单。连接刚建立时,发送方阻塞窗口为1,即只允许发送一个报文段,然后等待ACK;当收到该AC时,阻塞窗口从1增加为2,即可以发送两个报文段;当收到这两个报文段的ACK时,阻塞窗口就增加为4,这本质上是一种指数增加的关系。一旦发现报文丢失,发送方就把阻塞窗口减半,直至减少至最小的窗口(窗口至少应该包含一个报文段),这就是乘法减小

4、慢启动算法是发送方控制数据流量的方法,但是发送方阻塞窗口的增长本质上是以指数方式进行的,窗口的过快增长也可能使得数据流达到中间路由器的极限。因此,在慢启动的基础上,还需要附加一种拥塞避免算法:当阻塞窗口增加到拥塞发生前窗口大小的一半时,TCP进入拥塞避免阶段,以减小阻塞窗口增长的速度,在该阶段下,只有窗口中的所有报文段被确认之后,窗口值才加1,这就是加法增加。总之,发送方需要为慢启动算法和拥塞避免算法维持两个变量:一个阻塞窗口cwnd和一个拥塞避免启动门限 ssthresh

5、上述算法按照以下过程进行:
(1)对于一个新建立的连接,初始化阻塞窗口cwnd为1个报文段大小。
(2)发送方可以发送的数据量不能超过当前有效发送窗口的大小(有效发送窗口为阻塞窗口cwnd和接收方通告窗口中的小者)。拥塞避免是发送方使用的流量控制机制,而通告窗口则是接收方使用的流量控制机制。
(3)当发送方检测到拥塞时(超时或收到重复确认),ssthresh被设置为当前有效发送窗口大小的一半(但最少为2个报段)cwnd被设置为1个报文段大小。
(4)当有新数据被对方确认时,发送方就增加cwnd,增加cwnd的方式依赖于我们是处于慢启动阶段还是拥塞避免阶段:如果cwnd小于或等于ssthresh,则处于慢启动阶段;否则处于拥塞避免阶段。慢启动阶段采用慢启动算法更新cwnd,拥塞避免阶段采用拥塞避免算法更新cwnd
慢启动算法初始设置cwnd为1个报文段大小,此后每收到一个确认就加1,这会使窗口按指数方式增长。拥塞避免算法要求每次收到一个确认时将cwnd增加1/cwnd,当整个窗口内的数据被确认时,cwnd值只增加了1

三.快速重传与快速恢复

1、当收到一个失序的报文段时,接收方会将它挂接到ooseg队列上,同时向发送方返回一个ACK(期待的下一个字节),很明显,这个ACK一定是个重复的ACK,且这个重复的ACK被发送出去的时候不会有任何延迟。利用这个重复的ACK,让对方知道本端收到一个失序报文段,并告诉对方本端希望收到的序号。两种情况可能使发送方得到重复的ACK,一是某个序列靠前的报文段丢失,二是各个报文在网络中独立路由,序列靠前的报文段较其他报文段晚到达接收端,但在发送方,它无法区分这两种情况,因此它需要等待少量重复的ACK到来。假如这是由于报文独立路由引起的失序,则在重新排序的报文段被处理并产生一个新的ACK之前,接收方只可能产生1~2个重复的ACK。如果发送方一连串收到3个或3个以上的重复ACK,就非常可能是一个报文段丢失了。于是发送方就重传丢失的报文段,而无须等待超时定时器溢出,这就是快速重传算法,快速重传算法能在具有偶尔丢失的环境中达到很高的吞吐量

2、当快速重传发生时,连接处于快速重传模式,阻塞窗口直接被设置为有效窗口的一半(或更多),使得重传报文段的时候,其他报文段也能够处于双方的传输途中,如果在这样的情况下仍然收到重复的ACK,则每个ACK都将阻塞窗口增加一个报文段。在快速重传过程中仍执行慢启动算法使阻塞窗口不断扩大,原因在于,收到重复的ACK不仅仅告诉我们一个分组丢失了。由于接收方只有在收到另一个报文段,并将该报文段放入ooseg队列后,才会产生重复的ACK。这就说明,在收发两端之间仍然有流动的数据,而我们不想执行拥塞避免来突然减少数据流。当控制块退出快速重传模式后,阻塞窗口不会像超时那样被设置为1,相反,阻塞窗口被设置为ssthresh,连接直接进入拥塞避免阶段,这就是所谓的快速恢复

3、总之,快速重传与快速恢复算法步骤可以用下面的几步来简单描述:
(1)当收到第3个重复的ACK时,将ssthresh设置为当前有效发送窗口的一半(但最少为两个报文段大小)。重传丢失的报文段。设置cwnd为ssthresh加上3倍的报文段大小。
(2)每收到一个重复的ACK时,cwnd增加1个报文段大小(如果窗口允许,则发送新报文段)。
(3)当下一个确认新数据的ACK到达时,设置cwnd为ssthresh,即后续直接执行拥塞避免算法调整阻塞窗口

四.糊涂窗口与避免

1、基于窗口进行流量控制,会导致一种被称为糊涂窗口综合症的状况。当TCP接收方通告了一个小窗口,并且TCP发送方立即发送数据填充该窗口时,SWS就会发生。糊涂窗口综合症是一种能够导致网络性能严重下降的TCP现象,因为小单元报文段中IP首部和TCP首部这些字段占了大部分空间,而真正的TCP数据却很少。如果TCP的双方都是以小窗口通告和小报文段发送来实现通信,则会使TCP数据流包含很多非常小的报文段,而不是满长度的报文段,小报文的传输浪费了网络的大量带宽。糊涂窗口综合症可能由TCP连接双方中的任何一方引起。这是由于接收方可以通告一个小的窗口(而不是一直等到有大的窗口时才通告),而发送方也可以发送少量的数据(而不是等待更多的数据以便发送一个大的报文段)

2、为了避免糊涂窗口综合症的发生,接收方不必通告小窗口更新,而发送方不必发送小的报文段。在任何一方采取措施,都可以消除糊涂窗口综合症的发生。接收方解决的方法是不通告小窗口,通常的算法是接收方在小窗口更新的情况下不对发送方进行窗口通告,直到窗口可以增加一个最大报文段或者增加接收缓存空间的一半时,才向发送方通告。而在发送方如果TCP接收方通告了一个小窗口,发送方将不会发送队列中的第一个报文段,因为它比通告的窗口要大。相反,它会一直等待直至窗口有足够大的空间容下它。

3、接收方也可以使用推迟确认(delayed acknowledge)的方法避免糊涂窗口综合症,这时的做法是当接收窗口未达到满足要求的通告大小时,TCP推迟确认的发送。推迟确认需要把握好推迟的时间,否则可能导致接收方因为等不到确认而重传报段,TCP标准中规定,TCP实现对确认最多只能推迟500ms。同时,为了不影响发送方的RTT估计,接收方最好能保证每隔一个报文段进行一次确认。

五.零窗口探测

TCP接收方通过通告窗口大小来告诉发送方自己可以接收的数据多少,接收方采用这种方式来实现流量控制。假如接收方通告的窗口大小为0,这时会发生什么情况呢?这将完全阻止发送方的数据传输,直至通告窗口变为非0。发送方接到零窗口通告时,则会停止报文段的发送,直到接收方通告非0的窗口。如果一个非0窗口通告丢失了,则双方就有可能因为等待对方而使连接异常:接收方等待接收数据(因为它已经向发送方通告了一个非0的窗口),而发送方在等待允许它继续发送数据的非0窗口更新。为防止这种死锁情况的发生,发送方使用一个坚持定时器(persist timer)来周期性地向接收方查询,以便发现窗口是否已增大,这些从发送方发出的报文段称为窗口探查(window probe)报文。什么时候开始一个窗口探查,又什么时候停止探查呢?在这里,若检测到对方的通告窗口为0,则开启窗口探查;若检测到一个非0的窗口通告,则立即停止窗口探查

六.保活机制

如果一个TCP连接已处于稳定状态,而同时双方都没有数据需要发送,则在这个连接之间不会再有任何信息交互。然而在很多情况下,连接双方都希望知道对方是否仍处于活动状态。常见的状况是,服务器希望知道客户主机是否仍在线,如果客户主机崩溃或重启,那么原来的有效连接将变为无效。许多TCP/IP实现中,都提供了保活定时器来实现这种检测功能。TCP必须为服务器应用程序提供保活功能,服务器通常希望知道客户主机的运行状况,从而可以合理分配客户占用的资源。如果某条连接在两个小时之内没有任何动作,则服务器就向客户端发送一个保活探查报文。此时,客户主机可能处于下述4个状态之一:

(1) 客户主机依然正常运行,且从服务器仍可达。此时,当收到探查报文后,客户主机的TCP正常响应(返回ACK),服务器从客户主机的返回中可以判断对方仍工作正常。服务器将保活定时器复位,并在两小时以后重新发送探查报文,若在两小时定时到达之前,此连接上出现数据流动,则保活定时器复位。
(2) 客户主机已经崩溃,并且关闭或者正在重新启动,在这些情况下,客户主机都不会有任何响应。服务器也不可能收到探查报文的响应,此后,服务器还会发送9个这样的探查报文,每个报文间隔均为75s。如果服务器没有收到一个响应,它就认为客户主机已经关闭并终止连接。
(3) 客户主机崩溃并已经重新启动。此时客户主机会收到探查报文,但客户主机会判定当前连接无效,并向服务器返回一个复位报文。服务器收到复位报文后,结束该连接。
(4) 客户主机正常运行,但是从服务器不可达(通信故障)。这里的处理过程与情况2)相同,服务器因为多次发送探查报文,但不能收到任何响应,最后终止连接。

猜你喜欢

转载自blog.csdn.net/qq_21231413/article/details/88739450