协议三的问题:不能双向通信;如果发送方的定时器设定的初值较小的话,可能出现系统死锁。
但是用两条信道有一个问题:B从信道上得到A发来的消息,怎么知道是A发的是数据消息还是确认消息呢?同样对A也有这个问题。这个问题是可以解决的,一种方法是用不同的帧的格式,帧头上有定义一个帧格式字段,可以通过帧格式区分,B收到消息首先检查帧格式是数据帧还是应答帧,如果是数据帧,就交给网络层,如果是应答帧,说明刚刚发的帧收到了,应该在网络层取下一个数据发送给A。第二种方式是捎带确认,在捎带确认中,我并不专门给你发送一个确认帧,你给我发一个消息过来,我回一个消息,回的这个消息把刚才的确认消息附加在里面。A到B可以发多条数据,然后B再给A发一条信息,带上刚才的帧收到的确认,A就知道了这三条B都收到了。
滑动窗口协议,每一方都有一个发送窗口,发送窗口表示我每一次最多发送多少信息对方是有能力接收的,接收窗口是这一次我可以接收的量是多少。假如我们设定发送窗口是5,接收窗口是3,只考虑双向通信的一个方向,意味着我发送方连续可以发5个帧,接收方一次接收最大的量是三个帧。发送5个帧时,发送方就停下来了,接收方收了0号帧处理,收了1号帧处理,收了2号帧处理,处理完了就发送一个确认过去,这是接收方滑动窗口就转到3,4,5,确认发过去,发送方就知道0,1,2号帧收到了,这时可以发送的是3,4,5,6,7号帧,如果发送方的网络层还有信息要发送,这时候又可以发送5,6,7,如果接收方收到3,4,5号帧处理完了,发一个确认信号过去,就知道3,4,5号帧收到了,接下去又可以转动窗口。最多可以发5个,少于5个是可以的,多于5个就不行了。有了滑动窗口以后,每一次可以发送一批帧,而不是一个帧。
协议四:一位的停-等协议:发送和接收窗口为1的话,帧的编号就是0和1,所以发送过程就是:A发送一个帧以后,发送窗口满了,就必须停下来,等B,B再发送一个过来,B的发送窗口满了,又必须等待了,A收到了这个以后知道刚才这个帧B收到了,A再发下一个帧,到了B,B知道刚才这个帧A收到了,再发下一个帧,所以这也是一个停-等的过程,所以协议四称为一位的停-等协议,在停-等协议里面采用的机制是捎带确认,但是这个捎带确认是我收到一个帧必须确认一个,因为不发出对方不能发第二个帧过来,所以是一个帧确认一次,只不过确认信息加在帧后面捎带过去。现在协议部分发送方和接收方了。
如果现在有两个站点A和B,A首先发送,B等待发送,工作流程如下:首先主机A要初始化一个帧,在发送帧里面帧的序号是0,确认号是1,实际上这个确认号没有意义,因为对方还没发过信号。通过物理层发送出去这是初始化的时候做的工作,主机B由于这时没有帧,发送帧的序号为0,接收帧的序号也是0,然后处于一个等待状态,当主机A发过来一个0号帧,就是B主机收到了0号帧,B主机发送一个0号的确认,0号的确认表示为1,B现在等待1号帧,代表0号帧收到了,B发送自己的0号帧,到了A主机,知道刚发送的0号帧收到了,现在发送A的1号帧,B收到了这个帧以后,知道了刚发的0号帧收到了,现在B发1号帧。。。
协议4有个问题:A、B都抢着发送的问题,
协议4启动以后应该有一方先发送,有一方后发送。协议还是一个停等协议,信道的效率还是一个问题。
协议5和协议6主要针对发送过程中出错情况来处理的,如果连续发送的是一大批帧的话,因为信道是不可靠的,可能在发送过程中会有出错,但是由于现在的发送过程不是一个帧而是一批帧,当我意识到出错以后,可能后面已经发过来很多帧了,怎样对待出错帧,协议5和6就是对于这种情况下,两种不同的处理方式。
协议5:后退n帧的滑动窗口协议:发送窗口大于1,接收窗口等于1,当我们用3个比特来进行编码的话,也就是发送窗口为7,接收窗口为1,接收窗口为1代表每次接收方只等待一个帧,比如现在等待0号帧,来的是0号帧我收下了,来的是1号帧就扔掉了,来的是2号帧也扔掉了。。。对于发送方来讲,一下子可以发送很多的帧,对于接收方每次只等一个帧,如果这个帧发送中出错了,没有收到,接收方一直等待,后面的帧过来收不下来,所以后面的帧只能丢掉了,因此在发送的过程中有一个帧出错了,解决方法是把后面所有的帧都全部重发一遍,这就是协议5名字的由来,在出错以后已经发了N帧了,那么这n帧全部重发。比如发送窗口为7,发送帧的序号为0,1,2,3,4,5,6发过来,0号帧收到了,发来了一个确认,发送窗口就转过去了,于是第8个帧就可以发送出去了,1号帧收到了发送一个ACK,滑动窗口又转过去了,但是2号帧丢失了,3,4,5,6,7,8全部被接收方丢弃了,发送方知道丢弃的信息到2号帧的计时器时,然后发送方就重发2号帧,3,4,5,6,7,8.
只要帧号没到6,我就一直发送,在协议中要标记发送窗口有多大,已经发送了多少个帧了,当发送已满了,及时网络层还有数据要发送,也不发送了,所以这时要把网络层的请求关闭掉,所以协议5引入了enable_network_layer()和disable_network_layer(),这个过程说明允许不允许网络层的请求,在一开始的时候,发送窗口空着呢,一个还没发送,当然允许网络层发送,接收窗口是frame_expected,等待接收帧的序号,在当前窗口里面已经发送了多少个帧,ack_expected代表现在滑动窗口最早发出去的帧是多少,也就是等待的应答序号。next_frame_to_send代表下一个发送出去的帧的序号,表示尽管发送窗口大小为7,但是现在实际只发送出去3个,nbuffered表示目前发出了3个帧,下一个要发送的序号是3。
协议5有很多事件要处理,进去就是死循环,等待事件的发生。1.network_layer_ready:网络层有消息发送2.frame_arrival:有帧到达了3.cksum_err:校验和出错了4.timeout:刚才发送出去的某个计时器到时了。所有的事件处理好了就去检查下一步该怎么做,MAX_SEQ就是发送窗口的大小,nbuffer当前已经发出去的帧的数量。
所有发送窗口的帧都要缓存起来,帧的内容缓存在数组里面,nbuffered=nbuffered+1:表示发送的帧的个数加1,接下去就是发送数据,里面有帧的封装,启动计时器,发送完了之后帧的下一个发送序号加1,当收到一个帧的处理:
收到的这个帧使我等待的帧就将这个帧交给网络层,然后等待帧序号加1,如果不是我等待的帧就扔掉,不处理就是了。作为发送方有个发送窗口,发送方就要处理应答信号,在发过来的帧里面有一个ACK字段,就是带过来的确认号,发送方要看确认的到底是多少,在捎带确认中,其实并不是发送一个确认一个,最早发出去的是ack_expected,但确认的并不一定是这个号,而是可以比它后面的这些号,比如第一个发出去的是0,可以确认的是3,只要我刚才发过这个3号帧,意味着0,1,2,3都收到了,所以收到的处理是:这个收到的确认号是不是合法的确认号,合法的确认号就应该是落在我发送窗口已经发送出去的帧的序号之间,已经发出去的帧的序号就是ack_expected和next_frame_to_send之间,如果在这二者之间就转动滑动窗口。
这个地方比较关键的问题是计时器超时了,超时就意味着帧没有收到,协议 5中如果这个帧没有收到,那么也就是从这个帧到以后所有发出去的帧都没有收到,这些帧都要重发一遍,当这个事件发生的时候要处理的是全部重发,所以 next_frame从滑动窗口第一个发出去的位置开始 (ack_expected)重发nbuffered 个帧,一个一个帧去重发,
TIME_OUT处理:
从等待确认的帧开始全部重发。协议5关键的特点是一旦帧出错了,将所有的帧重发,对于后退n帧来讲适合的环境就是比较少出错的情况,要是信道不可靠,协议5不适用。
协议6:选择性重发滑动窗口协议:协议 6和协议 5的不同之处在于出错的话怎么解决。在协议 5中帧如果出错了,从出错的帧全部重发。协议6是一旦帧出错了,后面的帧已经传过了就不传了,所以又称选择性重发,只是重发我刚才出错的帧,刚才没有出错的帧就不发了,但是带来的麻烦是接收方的处理,对于协议 5来讲,是我要接收的帧就收下,不是要接收的帧就扔掉,但是对协议6来讲,现在不能扔掉了,很可能 2号帧没收到,但是收到3,4,5号帧,这些帧不能扔掉,必须把它们保存起来,所以在接收方必须保存收到的帧,所以对于接收窗口不能置为1(收一个帧),现在接收窗口要大于1,所以选择性重发,发送窗口、接收窗口都是大于 1。
如果发送窗口是 7,接收窗口也是 7的话,那么一下子可以发送 7个数据,对方也可以等待接收 7个数据,发送 0,1,2,3,4,5,6号帧,收到0 以后发送一个 ACK0,ACK0 以后发送窗口就转动,又发送一个 1号帧,收到 1号帧以后,发送 ACK1,发送窗口又转动,发送到 2号帧的时候,没有收到,丢掉了,因为发送窗口是 7,再发送一个 3,3号帧在我接收范围内,就把 3号帧收下来, 4,5,6,7,8都收下来,它们收下来都发送 ACK1,这时窗口满了,不能再发了也不能收了,都停下来,等到 2号帧计时器超时了,知道 2号帧没有收到,发送方就只发 2号帧,当 2号帧收到了,其实相当于 2,3,4,5,6,7,8都收到了,这时候就发送 ACK8过去。
定义了一个辅助计时器,在每个接收方都定义一个辅助计时器,这个计时器就记下到目前为止,有多久没给你发送确认了,如果计时器到时了,那就给发送方专门发送一个确认,这样就是发送方的滑动窗口转动了。
到了协议6,帧的所有格式都用到了,帧的类型,帧的序号,应答号,信息字段......