TCP协议通过使用连续ARQ协议和滑动窗口协议,来保证数据传输的正确性,从而提供可靠的传输。
一、ARQ协议
ARQ协议,即自动重传请求(Automatic Repeat-reQuest),是OSI模型中数据链路层和传输层的错误纠正协议之一。它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。如果发送方在发送后一段时间之内没有收到确认帧,它通常会重新发送。ARQ包括停止等待ARQ协议和连续ARQ协议,拥有错误检测(Error Detection)、正面确认(Positive Acknowledgment)、超时重传(Retransmission after Timeout)和 负面确认及重传(Negative Acknowledgment and Retransmission)等机制。
- 当发送窗口和接收窗口的大小都等于 1时,就是停止等待协议。
- 当发送窗口大于1,接收窗口等于1时,就是回退N步协议。
- 当发送窗口和接收窗口的大小均大于1时,就是选择重发协议。
(1)停止等待ARQ协议
要想弄明白为什么TCP要使用连续ARQ协议,首先需要弄清楚停止等待ARQ协议的原理。
TCP 连接是全双工的连接,也就是说在通信的时候,双方既是发送方,也是接收方。下面为了简化问题,只考虑一方发送,一方接受的情况。其中,A作为发送方,B作为接收方。
1.无差错情况
A发送分组M1,发送完就暂停发送,等待B的确认。B收到M1就向A发送确认。A在收到了对M1的确认后,就再发送下一个分组M2。依次下去发送剩余的数据...如下图所示:
2.出现差错
如果A发送的过程中出现差错,B在接收M1时检测出了差错,就丢弃M1,其他什么都不做(也不会通知A收到有差错的分组)。又或者A传送的过程中分组丢失了,以上这两种情况下,B不会发送任何信息。
既然说它是可靠传输协议,那自然有它可靠的方法:如果发生以上的情况,A只要超过了一段时间仍然没有收到确认,就认为刚才发送的分组丢失了,所以它会重传刚刚的发送过的分组,也就是所谓的超时重传。 超时重传的原理也很简单:发送方发送完一个分组后,就会设置一个超时计时器,如果超时计时器到期之前没有收到接收方发来的确认信息,则会重发刚发送过的分组;如果收到确认信息,则撤销该超时计时器。如下图所示:
这里应该注意的是:
- 既然发送方发送的分组可能丢失或者有差错,可能需要重传,那么它必须暂时保留已发送的分组副本,只有收到确认后,才清除这个副本。
- 分组和确认分组信息都应该有各自的编号,用来标示每一个分组和确认信息。(这样才知道需要发送哪个分组,收到了哪个分组的确认信息)
- 超时计时器设置的时间应该略长于分组传送往返时间。
3.确认丢失和确认延迟
没有正常进行通信,除了发送方出现问题外,接收方同时也可能存在问题。
例如,如果A发送了M1分组,到达B,B发送了M1确认信息,但由于网络原因,该确认信息丢失。那么这个时候,A在超时重传时间内,没有收到B的确认信息,而且它并不知道是自己的分组有差错、丢失,还是B发生的确认丢失了。因此,A会在超时重传过后,重传M1分组。
接收方B会采取这两个行动:
①B会丢弃M1分组,不向上层交付。(B之前已经收到过M1分组了)
②向A发送确认(因为A重发了,肯定重传时间内没有收到确认信息)
- 还有可能是另一种情况,就是B发送了确认,没有丢失,但是延迟了。也就是说,B发送的确认在A超时计时器过期后才到达。 这种情况下,A收到确认信息后会丢弃,然后重传刚才的分组,B收到后,丢弃重复的分组,并重传确认信息。
根据上述的确认和重传机制,我们就可以在不可靠的网络上实现可靠的传输。
4.信道利用率
停止等待ARQ协议的优点是简答,但也有很严重的确定,就是信道利用率太低。如下图所示:
信道利用率U = TD / (TD + RTT + TA)
(2)回退n帧的ARQ
在回退n帧的ARQ中,当发送方接收到接收方的状态报告指示报文出错后,发送方将重传过去的n个报文。回退N,发送窗口大于1,接收窗口等于1。允许发送方可以连续发送信息帧,但是,一旦某帧发生错误,必须重新发送该帧及其后的n帧。这种方式提高了信道的利用率,但允许已发送有待于确认的帧越多,可能要退回来重发的帧也越多。回退的基本原理图:
如果当前发送的是数据链路层上的最后一个帧(无论是数据帧还是确认帧),但不幸的是该帧出错或丢失了,此种情况也适用于中间某一帧开始的所有后继帧全部出错或丢失的情况(同样可以是数据帧或确认帧),那么发送端会一直等待下去,而且接收端对此也毫无察觉。
为了解决这个问题,需要采用超时机制。可以有多种定时方案,在早期方案中采用的一种是独立的定时器,发送端每发送一个数据帧就启动一次,当收到确认帧后,定时器复位;如果直到超时还没有收到确认帧,则重发该帧以及后继的帧。其原理如图下所示:
(3)连续ARQ协议
由于停止等待ARQ协议信道利用率太低,所以需要使用连续ARQ协议来进行改善。这个协议会连续发送一组数据包,然后再等待这些数据包的ACK。
发送方采用流水线传输。流水线传输就是发送方可以连续发送多个分组,不必每发完一个分组就停下来等待对方确认。如下图所示:
连续ARQ协议通常是结合滑动窗口协议来使用的,发送方需要维持一个发送窗口,如下图所示:
图(a)是发送方维持的发送窗口,它的意义是:位于发送窗口内的5个分组都可以连续发送出去,而不需要等待对方的确认,这样就提高了信道利用率。
- 连续ARQ协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。例如上面的图(b),当发送方收到第一个分组的确认,就把发送窗口向前移动一个分组的位置。如果原来已经发送了前5个分组,则现在可以发送窗口内的第6个分组。 接收方一般都是采用累积确认的方式。也就是说接收方不必对收到的分组逐个发送确认。而是在收到几个分组后,对按序到达的最后一个分组发送确认。如果收到了这个分组确认信息,则表示到这个分组为止的所有分组都已经正确接收到了。 累积确认的优点是容易实现,即使确认丢失也不必重传。但缺点是,不能正确的向发送方反映出接收方已经正确收到的所以分组的信息。比如发送方发送了前5个分组,而中间的第3个分组丢失了,这时候接收方只能对前2个发出确认。而不知道后面3个分组的下落,因此只能把后面的3个分组都重传一次,这种机制叫Go-back-N(回退N),表示需要再退回来重传已发送过的N个分组。
(4)选择性重传ARQ协议(Selective Repeat)
原理:
- 发送端连续发送数据包但对每个数据包都设有个一个计时器
- 当在一定时间内没有收到某个数据包的ACK时,发送端只重新发送那个没有ACK的数据包
这个方法的缺点是接收点收到的数据包的顺序可能不是发送的数据包顺序。因此在数据包里必须含有顺序字符来帮助接受点来排序。
- 接收点丢弃从第一个没有收到的数据包开始的所有数据包。
- 发送点收到NACK后,从NACK中指明的数据包开始重新发送
二、滑动窗口协议
滑动窗口协议在在发送方和接收方之间各自维持一个滑动窗口,发送发是发送窗口,接收方是接收窗口,而且这个窗口是随着时间变化可以向前滑动的。它允许发送方发送多个分组而不需等待确认。TCP的滑动窗口是以字节为单位的。
如下图所示,发送窗口中有四个概念::已发送并收到确认的数据(不在发送窗口和发送缓冲区之内)、已发送但未收到确认的数据(位于发送窗口之内)、允许发送但尚未发送的数据(位于发送窗口之内)、发送窗口之外的缓冲区内暂时不允许发送的数据。接收窗口中也有四个概念:已发送确认并交付主机的数据(不在接收窗口和接收缓冲区之内)、未按序收到的数据(位于接收窗口之内)、允许的数据(位于接收窗口之内)、不允许接收的数据(位于发送窗口之内)。
规则:
(1)凡是已经发送过的数据,在未收到确认之前,都必须暂时保留,以便在超时重传时使用。
(2)只有当发送方A收到了接收方的确认报文段时,发送方窗口才可以向前滑动几个序号。
(3)当发送方A发送的数据经过一段时间没有收到确认(由超时计时器控制),就要使用回退N步协议,回到最后接收到确认号的地方,重新发送这部分数据。
此外,TCP利用滑动窗口协议来进行流量控制,如下图所示:
问题:某些时候,由于发送端或接受端的数据很慢,会引起大量的1字节数据痛惜,浪费很多资源?
(1)发端的进程产生数据很慢时候,时不时的来个1字节数据,那么TCP就会1字节1字节的发送,效率很低。
解决方法(Nagle算法):
a、将第一块数据发出去
b、然后等到发送缓存有足够多的数据(最大报文段长度),或者等到收端确认的ACK时再发送数据。
c、重复b的过程(2)接受端进程由于消耗数据很慢,所以可能会有这么一种情况,收端会发送其窗口大小为1的信息,然后有是1字节的传输
解决办法(2种)
a、Clark方法:在接收缓存的一半变空,或者有足够空间放最大报文长度之前,宣告接收窗口大小为0
b、推迟确认:在对收到的报文段确认之前等待到足够的接收缓存,或者等待到一个时间段
三、Nagle
算法
Nagle算法:若发送应用进程把要发送的数据逐个字节地送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。当发送方接收对第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文段再发送出去,同时继续对随后到达的数据进行缓存。只有在收到对前一个报文段的确认后才继续发送下一个报文段。当数据到达较快而网络速率较慢时,用这样的方法可明显地减少所用的网络带宽。Nagle算法还规定:当到达的数据已达到 发送窗口大小的一半或已达到报文段的最大长度时,就立即发送一个报文段。该算法要求一个TCP
连接上最多只能有一个未被确认的未完成的小分组,在该分组的确认到来之前不发送其他的小分组。相反,TCP
收集这些少量的分组,并在确认到来之时以一个分组的形式发送出去。这样,就能够减少网络中小分组的数量,提高数据包的利用率。
算法优势:自适应,确认到达的越快,数据发送也就越快。