在计算机网络的世界中,大量的数据经由信道进行传输,通讯信道是不可靠,不安全的,可是不少时候咱们又但愿咱们可以可靠的收发数据。那么是否是能够设计一种通讯协议来保证数据的可靠性呢?缓存
答案固然是能够的。下面咱们就一步步来探究如何实现一个可靠的通讯协议(如下用rdt简称):安全
rdt1.0:在最开始的版本咱们假设信道是彻底可靠的,也就是说信道不会发生错误,也不会丢弃分组。服务器
那么在这种状况下,因为咱们肯定信道是可靠的,因此咱们不须要作任何处理,只须要发送方发送,接收方接收就彻底OK了。网络
rdt2.0:此时假设信道可能会发生位错误,可是全部的报文段都是按序到达的,而且不会在传输过程当中丢失。性能
这里有两个问题须要解决:怎么判断接收到的数据是错误的?若是接收到了错误的数据,应该如何从错误中恢复?计算机网络
先来解决第一个问题:数据在组装的时候,咱们能够在报文段中加入校验和,这样接收方就能够根据这个校验和判断接收到的数据是否发生了错误。设计
如今解决第二个问题:如今接收方接收到了一个错误的报文,那么对于接收方来讲,很容易,直接把错误的报文丢弃就好。但问题是发送方并不知道发送的报文在传输过程当中出错了。要解决这个问题,咱们就要加入新的消息机制。也就是说当接收方接收到了一个正确的报文段的时候,接收方给发送方回一个消息(ACK),确认我收到了正确的报文,能够继续发送。若是收到了错误的报文,就发一个NAK表示报文出错,须要发送方重传一个报文。htm
rdt2.1:在rdt2.0中咱们加入了ACK/NAK机制来避免错误,那么若是ACK或者NAK错了怎么办?发送方没有收到接收方的正确消息就会一直等待,此时会出现死锁。blog
这时能够想到的一个方法就是发送方若是收到错误的ACK/NAK就重传,可是可能会致使重复的分组。那么解决方法就是给每一个报文加入序列号。get
发送方描述:发送序列号为0的分组,等待确认消息。若是收到ACK,发送序列号为1的分组;若是收到NAK或者错误的ACK/NAK,重传序列号为0的分组。
接收方描述:若是收到正确序列号为0的分组发送ACK,错误就发送NAK,若是指望收到序列号为0的分组却收到了序列号为1的分组,发送ACK。
rdt2.2:在rdt2.1中咱们使用了ACK/NAK来做为消息传递机制,那么有没有可能咱们只用一个消息好比只用ACK来做为确认机制呢?答案固然是能够的,咱们能够在ACK中加入已经确认正确接收的序列号就行。
rdt3.0:在以前的协议中,咱们都是假设信道只会发生位错误,不会丢失。如今把这个限制去掉,数据在发送的过程当中可能会丢失。
基于上面的条件,前面的协议就可能会致使死锁(ACK丢失)。为了不死锁,咱们须要加入超时机制。也就是说当发送方等待必定的时间没有收到接收方的ACK的时候,就重传数据。
经过以上的协议设计,咱们已经基本可以保证通讯的可靠性了。可是咱们以前的协议都是基于停——等协议的(即发送数据,等待回执消息ACK),此时等待时间若是远远大于数据发送的时间,这个协议的效率是很低。rdt3.0也是如此,它的性能是不好的。致使rdt性能比较差的缘由是咱们使用了停等协议,一个很容易想到的改进方法就是使用流水线协议。即一次发送几个分组,而不是一个只发送一个分组,由此推出了滑动窗口协议。
什么是滑动窗口?看下面的一个图:
滑动窗口顾名思义,能够滑动的一个窗口。其实这就是发送方规定了一个大小固定的发送数据段,只有在这个窗口内的数据帧才容许发送。
滑动窗口分为两种:分别是GBN和SR。
GBN:GBN只有发送方有滑动窗口,接收方没有。发送方发送数据帧后,等待回执消息。若是收到ACK(采用累计确认),则确认已收到的数据帧,窗口向前滑动,继续发送数据帧。若是超时就重发全部未确认的数据帧(如图d是3和4)。接收方收到数据帧采用累计确认,若是收到乱序数据直接丢弃。例如收到0132四个数据帧,32直接丢弃,ACK确认1(累计确认)。
SR:SR协议发送方和接收方都有滑动窗口。相比于GBN,SR单独确认每一个分组。接收方对于乱序分组先缓存,单独回执接收到的分组。同时为每一个分组设置计时器。这样发送方就不须要像GBN同样,只须要重传未收到的分组就行了。
TCP的可靠数据传输:
TCP做为一个可靠数据传输协议,它都用了那些原理来保证可靠数据传输呢?
TCP协议使用的是滑动窗口,可是TCP既不是彻底的GBN也不是彻底的SR。TCP是为每一分组都单独设置定时器,并且采用的是累计确认。
为了保证TCP传输的性能,TCP的计时器=RTT平均值+“安全边界”。因为采用了这种机制,当出现超时状况时,超时时间间隔将加倍,这样就会致使超时时间过长。为了解决这个问题,TCP加入快速重传机制,即在超时发生以前,若是收到同一数据的三次ACK就触发重传。
TCP的流量控制:
接收方的接收buffer区大小有限,若是发送速度太快,而读取速度较小可能会致使buffer溢出。接收方会在报文首部加上一个RecWindow,告诉发送方还能够接收多少数据。这里会出现一个问题,若是发送方收到RecWindow==0的消息,该怎么办,一直等(死锁)固然不行。因此即便RecWindow为0的时候,发送方仍能够发送小段数据试探,直到接收方可以接收数据为止。
TCP的链接管理:
三次握手创建链接,四次挥手关闭链接。前一篇已经讲过,就不赘述。这里须要注意的是:client收到服务器发送的FIN,并向服务器发送ACK后会设置计时器,若是再次收到FIN就重发ACK,确保服务器已经关闭。
TCP的拥塞控制:
两种拥塞控制方法:AIMD(加性增,乘性减)和SS(慢启动)。
AIMD:发送速度一开始每次加一样的速度,当发生拥塞时,直接把速度减半。
SS:一开始速度很小,以后采用指数增加。