一、基本概念

在讲如何实现实现TCP可靠传输之前,我们需要了解几个基本概念。

(一)复位报文段

我们在TCP协议详解画出的TCP报文头中,报文首部有个标志位RST,当RST=1,表示复位报文段。在某些情况下,TCP连接的一端会向另一端发送携带RST标志的报文段,即 复位报文段,通知对方关闭连接或重新建立连接,这里介绍三种情况:

  • 当用户端程序访问一个不存在的端口时,目标主机给它发送一个复位报文段。
  • 异常终止连接。正常情况下,数据交换完成之后,一方给另一方发送FIN结束报文段 ,TCP提供了异常终止一个连接的方法,即给对方发送一个复位报文段,一旦发送了复位报文段,发送端所有排队等待发送的数据将会被丢弃。应用程序可以使用socket选项SO_LINGER来设置发送复位报文段,达到异常终止连接的目的。
  • 处理半打开连接。例如TCP一端关闭了连接,由于网络故障对方没有收到结束报文,对方误以为连接仍然正常,处于这种状态的连接称为半打开连接,此时如果对端向连接写入数据,就会收到本端回复的复位RST报文段。

(二)交互数据流与成块数据流

TCP按照携带应用程序数据长度可以分为两种:

  • 交互数据流:仅仅包含很少的字节。适合对实时性要求极高的应用程序,如telent远程登入,ssh安全外壳协议等。
  • 成块数据流:数据长度为TCP报文段允许的最大数据长度。适合对传输效率要求高的应用程序,如FTP文件传输协议。

(三)带外数据

有些传输层协议具有 带外数据的概念,用于迅速通告对方本端发生的重要事件。因此,带外数据比普通数据有更高的优先级,它应该总是立即被发送,而不论发送缓冲区中是否有排队等待发送的普通数据。

UDP没有实现带外数据传输,TCP也没有真正的带外数据,不过TCP利用其 头部中的紧急指针标志URG和16位紧急指针两个字段,给应用程序提供了一种传输紧急数据的方式。一般只有一个字节数据,当URG=1时,紧急指针指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据),发送TCP会把紧急数据插入到本报文段数据最前面,优先发送紧急数据。值得注意的是:即使窗口为零时也可发送紧急数据。

二、TCP如何实现可靠性传输?

我们一直在讲TCP是有连接,可靠的,面向字节流的传输协议,那么TCP是如何实现其可靠性呢?主要 从下列三个方面来保证TCP可靠性

  1. 保证数据能够到达对方。通过应答确认,超时重传保证数据的无差错到达,滑动窗口保证发送方发送数据和接收方速率匹配,拥塞控制保证发送方发送数据的速率与当前网络情况匹配来保证这一点,下面我们详细讲解这些机制。
  2. 保证数据不重复,不乱序。通过32位seq***保证,因为seq的初始值是随机生成的,在三次握手结束后,保证了通信的双方知道彼此的初始化seq,这个***要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序,TCP会用这个序号来拼接数据,这样就可以保证数据的不重复,有序。
  3. 保证数据不失真通过报文首部的16位校验和保证,添加12字节的伪首部进行检验,一般采取CRC冗余检验实现。

下面的文章我们讲详细讲解这些机制是如何实现TCP可靠性传输的。

三、可靠传输的工作原理之实现应答确认、超时重传

我们的网络不具备理想的传输条件,即不需要采取任何措施能够实现可靠传输。故就需要我们使用一些 可靠传输协议当出现差错时让发送方重传出现差错的数据,同时在接收方来不及处理收到的数据时,及时告诉发送方适当降低发送数据的数据即实现TCP传输数应答确认,超时重传,主要有两种协议:停止等待协议,连接ARQ协议

(一)停止等待协议

全双工通信的双方既是发送方也是接收方,我们现在假定A发送数据,B接收数据,因此A叫做发送方,B叫做接收方,传送给的数据单元都成为分组。

停止等待协议的核心概念就是每发送完一个分组就停止发送,等待对方确认,在收到确认后再发送下一个分组。

在使用停止等待协议时,A,B端会有以下几种情况出现:无差错情况,出现差错,确认丢失,确认迟到,我们对这几种情况进行描述。

【1. 无差错情况】

A发送的每一个分组B都收到了,A也收到了B的确认信息。如下图所示:
五、TCP保证可靠性传输详解

【2. 出现差错情况】

出现差错的情况一般有两种:

  • B接收M1时检测出了差错
  • M1在传输过程中丢失了。

这时B就会自动丢弃有差错的分组,并不会去通知A;A只要超过一段事件仍然没有收到确认,就认为刚才发送的分组丢失了,就重传前面发送的分组,这个就是 超时重传机制,如下图所示:
五、TCP保证可靠性传输详解

实现超时重传机制

  • 每发送的一个分组设置一个超时计时器,这个时间的设置采用TCP提供的自适应算法得到,如果在超时计时器到期之前收到对方的确认,就撤销已设置的超时计时器。
  • 否则就进行重传

图中A为每一个发送的分组都设置了一个超时计时器,只要A在超时计时器到期之前收到了相应的确认,就撤销该超时计时器。

超时重传对发送数据端A有以下要求

  • A在发送完一个分组后,必须暂时保留已发送的分组分副本,在超时重传时使用,只有在收到相应的确认后才能清除暂时保留的分组副本。
  • 分组和确认分组都必须进行编号,这样才能明确是哪一个发送出去的分组收到了确认,哪一个没有收到确认。
  • 超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些

【3. 确认丢失】

B所发送的对M1确认丢失了A在设定的超时重传时间内没有收到确认,但并无法知道是自己发送的分组出错,丢失,或者是B发送的确认丢失了。因此A在超时计时器到期后就要重传M2。这时B又收到了重传的分组M2,这时会采取两个行动:

  • 第一,丢弃这个重复的分组M2,不向上层交付
  • 第二,向A发送确认,不能认为自己已经发送过确认就不再发送,因为A之所以重传M2就表示A没有收到对M2的确认。如下图:
    五、TCP保证可靠性传输详解

【4. 确认迟到】

当传输过程没有出现差错,但B对分组M1的确认迟到了,A会收到重复的确认,对重复的确认的处理很简单:收下后就丢弃,B仍然会收到重复的M1,并且同样要丢弃重复的M1,并重传确认分组,如下图所示:

五、TCP保证可靠性传输详解

【总结】

  • 通常A最终总是可以收到对所有发出的分组的确认,如果A不断重传分组但总是收不到确认,就 说明通信线路太差,不能进行通信
  • 使用上述的 应答确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信

像上述这种可靠传输协议常称为 自动重传请求ARQ(Automatic Repeat reQuest,意思是重传的请求是自动进行的,接收方不需要请求发送方重传某个出错的分组。

(二)连续ARQ协议

滑动窗口协议就是使用的的连续ARQ协议,我们先来看一下什么是连续ARQ协议。

下图表示发送方维持的发送窗口,它的意义是:位于发送窗口内的5个分组都可以连续发送出去,而不需要等待对方的确认,这样,信道的利用率就提高了。
五、TCP保证可靠性传输详解
连续ARQ协议规定: 发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。 如下图表示发送方收到了对第一个分组的确认,于是就把发送窗口向前移动一个分组的位置,如果原来已经发送了前5个分组,那么现在就可以发送窗口内的第6个分组了。

五、TCP保证可靠性传输详解
接收方一般都采取累积确认的方式 ,这就是说,接收方不必对收到的分组逐个发送确认,而是在收到几个分组后,对按序到达的最后一个分组发送确认,这样就表示:到这个分组位置的所有分组都已正确收到了。

累积确认有优点也有缺点:

  • 优点容易实现,及时确认丢失也不必重传。
  • 缺点不能向发送方反映出接收方已经正确收到所有的分组的信息。

例如,如果发送方发送了前5个分组,而中间的第3个分组丢失了,这时接受方只能对前两个分组发出确认。发送方无法知道后面三个分组的下落,而只好把后面的三个分组都再重传一次这就叫做Go-back-N(回退N),表示需要再退回来重传已发送地N个分组。可见当通信线路质量不好时,连续ARQ协议会带来负面的影响。

故TCP可靠传输的应答确认和超时重传可以通过停止等待协议,或者连续ARQ实现。

四、TCP可靠传输之滑动窗口流量控制

(一)滑动窗口

在TCP报头中有一个字段叫做接收通告窗口,这个字段由接收端填充是接收端告诉发送端自己还有多少缓冲区可以接收数据,于是发送端就可以根据这个接收端的处理能力来发送数据这样就不会导致接收端处理不过来。保证了发送方发送数据和接收方速率匹配。

这个发送窗口的大小由接收端填充的接收通告窗口的大小决定的,并且窗口的位置会随着发送端数据的发送和接收到接收端对数据的确认而不断地向右滑动将之称为滑动窗口。

【窗口类型:】

  1. 接收端窗口rwnd接收缓冲区的大小,接收端将此窗口值放在TCP报文的首部中的窗口字段,传送给发送端。存放按序到达的,但尚未被接收应用程序读取的数据和未按序到达的数据。
  2. 拥塞窗口cwnd发送端缓冲区的大小,用来存放准备发送的数据和已发出但尚未确认的数据。
  3. 发送窗口swnd:发送窗口的上限值=Min=[rwnd,cwnd],存放已发送未确认的数据和可发送但还没发送的数据

如下图所示,就是一个滑动窗口的变化:

五、TCP保证可靠性传输详解
从上图我们可以得出以下的 结论

  • 发送窗口表示,在没有收到接收端确认的情况下,发送端可以连续把窗口内的数据都发送出去,凡是已经发送的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用
  • 发送窗口里面的序号表示允许发送的序号,窗口越大,发送方就可以在收到对方确认之前连续发送更多的数据,因而可能获得更高的传输效率,但接收方必须来得及处理这些收到的数据。
  • 发送窗口后面部分表示已经发送且收到了确认,这些数据显然不需要再保留了。而发送窗口前面部分表示不允许发送的,因为接收方都没有为这部分数据保留临时存放的缓存空间

发送窗口的 变化情况一般有两种

  1. 发送窗口通常时不断向前移动。表示收到了新的确认
  2. 也有可能不动。一是没有收到新的确认,对方通知的窗口大小也不变;二是收到了新的确认但对方通知窗口缩小了,使得发送窗口正好不动。

TCP标准不赞成发送窗口向后移动。

(二)流量控制

TCP协议是利用滑动窗口实现流量控制的。一般来说,我们总是希望数据传输的更快一点,不会一次只发一个字节,但是如果发送把数据发的过快,接收方可能来不及接收,这就会造成数据的丢失。 所谓流量控制就是让发送方的发送速率不要太快,要让接收方来的及接收。

利用滑动窗口机制可以很方便的在TCP连接上实现对发送方的流量控制。我们看下面的例子:

假如A向B发送数据,在连接建立时,B通过报文段首部告诉A:“我的接收窗口rwnd=400”,因此,发送方即A的发送窗口不能超过接收方给出的接收窗口的数值。这里的TCP窗口单位是字节,不是报文段。设置一个报文段DATA为100字节长,数据报文段seq的初始值设为1,ack表示确认字段的值,那么流量控制如下图:

五、TCP保证可靠性传输详解
在整个过程中,接受方的主机B进行了 三次流量控制

  1. 第一次把窗口减少到rwnd=300,这时发送端的发送窗口缩小。
  2. 第二次又减到rwnd=100。
  3. 第三次减少到rwnd=0, 即不允许发送方再发送数据了。我们将这个窗口称为零窗口,这个状态将持续到主机B重新发出一个新的窗口值位置。

注意,B向A发送的三个报文段都设置了ACK=1,只有再ACK=1时确认号字段才有意义。

可以看到 通过滑动窗口,实现了流量控制,让发送方A发送的数据都可以被接受端B处理,保证了数据的可靠到达。

(三)零窗口问题

在上图中B最后给A发送了零窗口,此时A已经不能发送数据了,当B的接收缓存有了一些存储空间时, B向A发送了rwnd=400的报文段,但是这个报文段在传送过程中丢失了,A一直等待收到B发送的非零窗口的通知,而B也一直等待A发送的数据,如果没有其他措施,这种相互等待的死锁局面将一直延续下去,这就是零窗口问题。

TCP规定,即使设置为零窗口,也必须接收以下几种报文段:

  • 零窗口探测报文段
  • 确认报文段
  • 携带紧急数据的报文段。

【解决零窗口问题:】

为了解决这个问题,TCP为每一个连接设有 一个持续计时器

  • 只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器
  • 若持续计时器设置的时间到期,就发送一个 零窗口探测报文段(仅携带1字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值
  • 如果窗口仍然是零,那么收到这个报文段的一方就重新设置持续计时器,如果窗口不是零,那么死锁的僵局就可以打破了

(四)糊涂窗口综合征

糊涂窗口综合征,有时会使TCP的性能变坏。

设想一种情况:TCP接收方的缓存已满,而交互式的应用进程一次只从接收缓存中读取1个字节,这样就使得接收缓冲区仅腾出1个字节:

  • 接收端向发送方发送确认,并把窗口设置为1个字节,但发送的数据报是40字节长(20IP头+20TCP头)
  • 接着,发送方又发来1个字节的数据,那么数据报长度为41字节,固定头部40,真实数据1字节,接收端发回确认,窗口仍然设置为1个字节。

这样循环进行下去,使网络的效率很低,这就是我们说的糊涂窗口综合征,又称为小窗口问题,总结来说就是每次发送很小的字节,却需要40字节的固定头部,数据报固定开销远远大于数据部分,这样会导致网路效率低。

【解决糊涂窗口综合征的办法:】

  • 接收方:可以 让接受方等待一段时间,使得接收缓存已有足够空间容纳一个最长的报文段,或者 等到接收缓存已有一半空闲的空间。只要出现 这两种情况之一,接收方就发出确认报文,并向发送方通知当前窗口大小。
  • 发送方发送方也不要发送太小的报文段,否则会引起接收端的多次确认,浪费内存,而是把数据报积累成足够大的报文段,或达到接收方缓存的空间的一般大小,这就是Nagle算法。

这两种办法可配合使用使得在发送方不发送很小的报文段的同时,接受方也不要在缓存刚刚有了一点小的空间就急忙把这个很小的窗口大小信息通知给发送方。

(五)Nagle算法

解决糊涂窗口综合征就可以用到Nagle算法,在TCP的实现种广泛使用Nagle算法。

【对算法的功能描述如下:】

  • 若发送应用进程把要发送的数据 逐个字节的送到TCP的发送缓存,则 发送方就把第一个数据字节先发出去,把后面到达的数据字节都缓存起来。
  • 当发送方收到第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文段发送出去, 同时继续对随后达到的数据进行缓存。

只有在收到对前一个报文段的确认后才继续发送下一个报文段,当数据到达较快,而网络速率较慢时,用这样的方法可明显地减少所用的网络带宽。

Nagle算法还规定, 当到达的数据已达到发送窗口大小的一半或已达到报文段的最大程度时,就立即发送一个报文段。

加油哦!????。

相关文章:

  • 2021-08-26
  • 2021-11-12
  • 2021-12-10
  • 2022-02-20
  • 2022-12-23
猜你喜欢
  • 2021-08-20
  • 2021-11-03
  • 2022-12-23
  • 2022-12-23
  • 2021-09-11
相关资源
相似解决方案