TCP/IP协议浅析二

可靠数据传输

在计算机网络的世界中,大量的数据经由信道进行传输,通信信道是不可靠,不安全的,但是很多时候我们又希望我们能够可靠的收发数据。那么是不是可以设计一种通信协议来保证数据的可靠性呢?

 答案当然是可以的。下面我们就一步步来探究如何实现一个可靠的通信协议(以下用rdt简称):

rdt1.0:在最开始的版本我们假设信道是完全可靠的,也就是说信道不会发生错误,也不会丢弃分组。

那么在这种情况下,由于我们确定信道是可靠的,所以我们不需要做任何处理,只需要发送方发送,接收方接收就完全OK了。

rdt2.0:此时假设信道可能会发生位错误,但是所有的报文段都是按序到达的,并且不会在传输过程中丢失。

这里有两个问题需要解决:怎么判断接收到的数据是错误的?如果接收到了错误的数据,应该如何从错误中恢复?

先来解决第一个问题:数据在组装的时候,我们可以在报文段中加入校验和,这样接收方就可以根据这个校验和判断接收到的数据是否发生了错误。

现在解决第二个问题:现在接收方接收到了一个错误的报文,那么对于接收方来说,很容易,直接把错误的报文丢弃就好。但问题是发送方并不知道发送的报文在传输过程中出错了。要解决这个问题,我们就要加入新的消息机制。也就是说当接收方接收到了一个正确的报文段的时候,接收方给发送方回一个消息(ACK),确认我收到了正确的报文,可以继续发送。如果收到了错误的报文,就发一个NAK表示报文出错,需要发送方重传一个报文。

rdt2.1:在rdt2.0中我们加入了ACK/NAK机制来避免错误,那么如果ACK或者NAK错了怎么办?发送方没有收到接收方的正确消息就会一直等待,此时会出现死锁。

这时可以想到的一个方法就是发送方如果收到错误的ACK/NAK就重传,但是可能会导致重复的分组。那么解决方法就是给每个报文加入序列号。

发送方描述:发送序列号为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协议使用的是滑动窗口,但是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:一开始速度很小,之后采用指数增长。

posted @ 2018-06-06 20:48  迷失的小菜包  阅读(279)  评论(0编辑  收藏  举报