TCP协议是如何保证可靠传输的

 

 

题外话:

1、UDP:

(1)UDP,user datagram protocol,用户数据报协议,不提供复杂的控制机制,利用IP提供面向无连接的通信服务,并且它是将应用程序发送过来的数据包在收到的那一刻,立即按照原样发送到上的一种机制。

(2)即使在网络拥堵的情况下,UDP也无法进行流量控制等避免网络拥塞的行为。此外,在传输过程中如果出现丢包,UDP也不负责重发,甚至当数据包的到达顺序乱掉之后也没有纠正顺序的功能。因此,如果需要这些细节控制的话,就需要在采用UDP协议的应用层去作出处理。

(3)由于UDP面向无连接,所以它可以随时向对端发送数据包,再加上UDP本身的处理既简单右高效,所以UDP经常用于如下几个方面:
数据包总量比较少的通信,比如DNS、SNMP。
视频、音频等对实时性要求比较高的多媒体通信。
广播通信、多播通信。
2、TCP:

(1)TCP,控制传输协议,和UDP的差别很大,它充分实现了数据传输时的各种控制功能:

针对发送端发出的数据包的确认应答信号ACK、、、针对数据包丢失或者出现定时器超时的重发机制、、、针对数据包到达接收端主机顺序乱掉的顺序控制、针对高效传输数据包的流动窗口控制、、、针对避免网络拥堵时候的流量控制、、、针对刚开始启动的时候避免一下子发送大量数据包而导致网络瘫痪的慢启动算法和拥塞控制。

(2)而这些在UDP中都是没有的!此外,TCP作为一种面向有连接的控制传输协议,只有在确认对端主机存在时才会发送数据,从而可以控制通信流量的浪费。

言归正传:TCP通过序列号、检验和、确认应答信号、重发控制、连接管理、窗口控制、流量控制、拥塞控制实现可靠性。

1、通过序列号和确认应答信号提高可靠性。

(1)如图1 所示:在TCP中,当接收端主机接收到来自客户端主机的数据包之后,接收端主机会返回一个已收到消息的通知,这个通知消息就叫做确认应答信号ACK包。

 


(2)TCP通过肯定的确认应答信号ACK包来实现可靠的数据传输。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端主机了。反之,若没有收到确认应答,则数据包丢失的可能性比较大。

(3)情况1:数据包丢失的情况:

如图2 所示,在特定的等待时间间隔内发送端主机还是没有收到来自接收端的确认应答,发送端就可以认为数据已经丢失了,并且进行重发处理。由此,即使产生了丢包也能够保证数据到达对端,实现可靠传输。

(4)情况2:确认应答丢失的情况:

如图3 所示,未收到对端的确认应答信号并不一定意味着数据包的丢失,也有可能是因为对端主机已经收到了该数据包,但是针对该数据包的确认应答包在回送途中丢失了而已,或者没有丢失、只是因为网络中的其他一些原因延迟很长时间才到达源主机。

此时,源主机只会按照重发机制重发数据包而已,但是这对于对端主机来说简直就是灾难,因为对端主机会反复接收到很多重复的不必要的数据,而为了对上层应用协议提供可靠的传输,对端主机不得不丢掉这些重复的数据包。因此,这对网络拥塞的形成造成了很大的促进。

所以,需要一种机制来识别是否已经接收到了这个数据包、又能够判断数据包是否需要接收。

上述这些 确认应答处理、重发控制、重复处理 都可以使用数据包的序列号来进行实现。

如图4 所示,序列号 是指按照顺序给发送数据包中的每一个字节都标识上号码编号,接收端主机 根据接收数据TCP包首部中的序列号和数据长度,来将自己下一步应该接收的序列号作为确认应答返送回去。就这样,根据序列号和确认应答信号,TCP可以实现可靠传输。


2、超时重发如何确定呢?

(1)重发超时,是指在发送端主机在重发数据包之前,等待接收端主机的确认应答信号到来的“那个特定的时间间隔”。

如果超过了这个特定的时间间隔仍未收到ACK包,发送端则会进行重发。

(2)那这个特定的时间间隔如何确定呢? TCP为了保证在任何网络下都能够提供比较高的传输性能,并且在任何网络下都能够保持住这一特性,它在每次发包时都会计算往返时间及其偏差,将这个“往返时间+偏差”,重发超时就是比这个总和值要稍大一点的值。

(3)在Windows系统中,超时时间都是以0.5s 为单位进行控制的,因此超时时间都是0.5s 的整数倍。不过由于最初的数据包还不知道往返时间,所以最初的重发超时时间一般设置为6s 左右。

另外,若是进行了重发处理,则第二次、第三次的等待的超时时间会以2倍、4倍的指数函数增长,以此类推。

但是,数据包也不会倍无限次的反复的进行重发。当重发次数达到一定次数过之后,如果发送端还是接收不到对端主机的ACK包,那么发送端主机就会认为网络或者对端主机出现了异常,进行强制关闭连接,并且通知应用程序异常强制终止。

3、TCP的连接管理。

(1)TCP是面向有连接的数据通信,也就说在进行实际的数据包的收发之前,会先做好通信两端主机的准备工作:TCP三次握手!

见博客:20170906_我是如何讲清楚TCP的三次握手和四次挥手的

(2)在双端主机进行数据的交互完成过之后,会进行TCP连接的断开处理。见上面的博客。

4、TCP是以段为单位进行数据包的发送的。

(1)在建立TCP连接的同时,也可以确定发送数据包的单位,称之为“最大消息长度”:MSS。最理想的情况是,最大消息长度MSS正好是IP层中不被分片处理的最大数据长度。

(2)TCP在传送大量数据的时候,是以“段=MSS的大小”将数据进行分割发送的,进行重发时也是以MSS为单位的。

(3)如图5 所示:最大消息长度——MSS是在三次握手的时候,在两端主机之间被计算得出的。两端主机在发出“建立TCP连接请求的SYN包”时,会在SYN包的TCP首部中写入MSS选项,告诉对方自己所能够适应的MSS的大小,然后发送端主机会在两者之间选择一个较小的MSS值投入使用。


5、利用滑动窗口控制提高速度。

(1)如图6 所示:TCP是以一个段为单位进行数据的传输的,每发送一个段,就会等待对端主机的针对这个段的确认应答信号ACK,但这样的传输方式的缺点也很明显,就是:当数据包的往返时间越长,通信性能越低。

 

(2)为了解决这个问题,TCP引入了窗口这个概念,即使在往返时间比较长的情况下,它也能够控制网络性能的下降。如图7 所示:确认应答包不再以每个段为单位进行确认了,而是以更大的单位进行确认,转发时间将会被大幅度的缩短。也就是说,发送端主机在发送了一个段之后,没必要一直等待对端主机的确认应答信号,而是继续发送。

(3)窗口大小,指的就是无需等待接收端主机的确认应答信号而可以持续发送的数据的最大值,或者说段的最大值,比如图7 所示的窗口大小是4 个段。 滑动窗口控制的实现,使用了大量的缓冲区,通过对多个段的数据同时进行确认应答来实现高效传输。

(4)如图8 所示,发送数据中的高亮部分正是前面提到的窗口。在这个窗口内的数据即便没有收到确认应答也可以发送出去,此外发送端主机在等到对端主机的确认应答之前,必须在缓冲区中保留这部分数据,以便数据包的丢失而重发。


(5)在滑动窗口以外的数据,包括尚未发送出去的数据,以及已经确认对端收到的数据,当发送端确认对端已经收到数据包之后,此数据包就可以从缓冲区中清除了。

当收到确认应答信号过之后,会把滑动窗口的位置滑动到确认应答的序列号的位置,这样就可以顺序的将多个段同时发送以提高通信功能了。这就是滑动窗口控制。

6、滑动窗口控制与重发控制。

(1)在使用了窗口控制中,如果出现了丢包怎么办呢?

首先,我们先考虑接收端已经收到数据包只是反馈的确认应答包ACK包在途中丢失了的情况。

如图9 所示:在这种情况下,数据是已经被对端主机成功接收了的,是不需要进行重新发送的。然而,在没有使用窗口控制的前提下,没有收到确认应答包的数据包都会被重发。但是,在使用了窗口控制以后,就如图9 所示,某些应答包即使丢失了也无需重发,这也提高了传输效率。

 

(2)其次,我们再来考虑一下某个数据包丢失的情况。

如果当接收端主机接收到一个自己应该接收的序列号之外的数据包时,它会一直对当前接收到的数据包返回确认应答包。

因此,如图10 所示:当某一个数据包丢失以后,发送端会一直接收到序列号为1001的确认应答包,这个确认应答包好像是在提醒发送端主机“我现在想要接收的数据包序列号是1001开始的”。

因此,在滑动窗口比较大的情况下,同一个序列号的确认应答将会被重复不断地返回。而发送端主机如果 连续 3 次 接收到同一个确认应答包,就会将其对应的数据重发,这种机制比之前提到的“超时重发”更加高效,所以被称之为“高速重发控制”。

7、流量控制。

(1)发送端主机会根据自己的实际情况发送数据,而接收端也会跟据自己的实际情况接收数据。因此,TCP协议提供了这样一种机制:可以让发送端主机根据接收端主机的实际接收能力来控制自己发送的数据量。这就是所谓的“流控制”。

(2)具体操作就是:接收端主机向发送端主机通知自己所能够接收数据的大小,于是发送端主机就会发送不超过这个限度的数据,该大小被称之为“通告窗口”,就是之前提到的“控制窗口”,这个值是由接收端主机决定的。

TCP首部中,专门有一个字段用来通知“窗口大小”,接收端主机可以将自己的实际接收缓冲区大小写入到这个字段中通知给发送端,这个值越大说明网络的吞吐量越大。

不过,接收端主机的缓冲区一旦面临数据溢出,就会主动减小窗口的大小再次发送给发送端主机,从而可以控制数据发送量。也就是说,发送端主机会根据接收端主机的指示,对发送的数据量进行控制,这也就形成了一条完整的TCP流量控制。

(3)如图11 所示:当接收端主机收到了从3001号开始的数据包之后其缓冲区即将满,不得不暂时停止接收数据,于是把窗口大小设置为0,然后通知该发送端。之后,发送端在收到新的窗口更新值的通知之后通信才得以继续进行。

如果这个滑动窗口的更新通知在传输途中丢失了,则很有可能导致无法继续进行通信。为了避免此种问题的发生,发送端主机会时不时的发送一个叫做“探测窗口”的数据包,次数据包仅含有一个字节,以获取最新的窗口大小。


8、拥塞控制。

(1)有了TCP的滑动窗口控制,收发主机之间即使不再以一个“段”为单位发送确认应答信号,也能够连续发送大量数据包。然而,如果在通信刚开始的时候就发送大量的数据包,也有可能会导致其他问题。

问题的发生: 要知道,计算机网络都处在一个共享的环境中,因此也有可能是因为其他的主机之间的通信使得整个网络出现拥堵。所以,在网络拥堵时,如果突然发送一个较大量的数据包,极有可能导致网络的瘫痪。

(2)TCP为了防止这种问题的发生,在通信一开始的时候会通过一个叫做“慢启动”的算法对发送的数据量进行控制。

首先,为了在发送端调节所要发送的数据量,定义了一个叫做“拥塞窗口”的概念。于是,在慢启动刚开始的时候,把这个拥塞窗口设置为1个MSS(1个数据段)发送数据,之后每收到一个接收端主机的确认应答信号ACK包 就把这个拥塞窗口的数值加1。然后,在发送数据的时候,把拥塞窗口和滑动窗口的大小作比较,按照它们当中较小的那个值来发送比其还要小的数据量。

不过,随着数据包的每次的往返,拥塞窗口会以1、2、4、8等指数函数的增长,拥堵状况激增甚至导致网络拥塞的发生。为了防止这些,又引入了“慢启动阈值”的概念,只要拥塞窗口超过这个阈值,在每收到一个ACK包的时候,只允许以下面这种方式来增大拥塞窗口:(1个数据段的字节数的平方 / 拥塞窗口的字节数)。这样的话,拥塞窗口越大,确认应答的数目也会增加,但是其涨幅却逐渐减少,因此会导致拥塞窗口是直线形式的上升。

TCP在刚开始通信的时候,并没有设置慢启动阈值,而是在超时重发时,才会把慢启动阈值设置为当前窗口的一半大小。

(3)由重复确认应答而触发的高速重发与超时重发机制的处理是不一样的。因为前者要求至少 3 次的确认应答包到达对方主机才会触发,相比后者网络拥堵的程度较轻一些。

而由重复确认应答进行高速重发控制时,慢启动阈值的大小被设置为当时窗口大小的一半,然后将窗口大小设置为该慢启动阈值+3个MSS的大小。

(4)有了这样的一种控制过之后,TCP的拥塞窗口的变化曲线 如图12 所示。由于窗口的大小会直接影响数据被转发的吞吐量,所以一般情况下,窗口越大,越会形成高吞吐量的通信。


9、纳格算法:Nagle算法。

(1) TCP/IP协议中,无论发送多少数据,总是要在数据前面加上协议头。同时,对方接收到数据,也需要发送ACK表示确认。

为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP 希望每次都能够以MSS尺寸的数据块来发送数据)。

(2) Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。 Nagle算法的基本定义是:在任意时刻,最多只能有一个未被确认的小段。

所谓“小段”,指的是小于MSS尺寸的数据块。所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。

(3)这是因为TCP/IP 中不仅仅有Nagle算法,还有一个TCP确认延迟机制 。当Server端收到数据之后,它并不会马上向client端发送ACK,而是会将ACK的发送延迟一段时间(假设为 t),

它希望在 t 时间内server端会向client端发送应答数据,这样ACK就能够和应答数据一起发送,就像是应答数据捎带着ACK过去。

posted on 2017-02-28 22:13  WeirdLang  阅读(174)  评论(0编辑  收藏  举报