【计算机网络】流量控制协议

一、Utopian Simplex Protocol(乌托邦)

最简单的协议,假设信道是单工的,无差错的,且接收方有无限的缓冲区。

所以发送方就可以一直发

问题:现实情况比这个恶劣的多。

二、Simplex Stop-and-Wait Protocol for an Error-Free Channel(简单停等)

假设:单工信道,无差错,接收方是有限的缓冲区。

发送方发送数据,然后停下来等待接收方的ack,收到ack之后再发数据。这样接收方就可以不发ack来控制发送的速度。

问题:

1、如果信道不是无差错的,那么接收方算了CRC之后发现不对,就会丢弃包,不发ack,这时发送方的timer超时,就会重传。

2、如果数据帧丢了,那么发送方就会收不到ack,timer超时重传。

3、如果ack丢了,那么同样发送方就会收不到ack,timer超时重传。可是这就会有一个问题

 发送方重传的是一样的东西,这样接收方就会收到同样的帧,可接收方不知道是同样的帧,这时就需要给数据帧加序号。

可是这样还没完,接收方收到重复的帧后,接受方发现是重复的序号,就丢掉了,不发ack,可发送方不知道啊,发送方觉得是这一帧又没发到,timer到了就又重传。所以这时就需要给ack帧加序号,加上这两个序号,就是第三个协议。

三、Stop-and-Wait ARQ(停等ARQ)

 就是用0和1给数据和ack编号,这样就解决了重复数据帧和延迟ack的问题。

四、One-Bit Sliding Window Protocol

窗口大小为1的滑动窗口协议,其实就是停等,只不过这个是双工的,刚才的停等是单工的信道。

工作流程如下:

1、发收双方窗口大小都为1,初始窗口状态都一样,发送方准备发送序号为0的数据,接收方等待接收序号为0的数据,

2、发送方发送数据,把该数据标记为已发送待确认

3、接收方收到数据,crc确认后将数据交给上层,发送ack给发送方,并同时把窗口向右滑动,表示下一个待收的数据序号为1

4、发送方收到ack,将窗口向右滑动,准备发送下一个序号为1的数据,如此反复。

问题:这样对于一些带宽时延积较大的信道,会导致低效,比如卫星信道,数据的发送时延很短,但是传播时延很长,发送方花了很短的时间将数据发送出去,剩下很大一部分时间都在等待数据发给接收方,然后接收方回ack,时间主要都用到这两次传播时延上了,效率很低。

五、Protocol Using Go Back N

还是滑动窗口,这次发送窗口有很多,但是接收窗口还是一个,这个协议采用了累计ack的方法。

1、正常情况

看这个正常情况的例子,发送窗口大小是3,按顺序发0、1、2帧,接收方一开始窗口在0那,收到0号帧之后,由于是累计确认,所以不发ack,把窗口向右滑,等待1号帧,收到1号帧后,滑动窗口,回一个ack1,表示0和1号帧都收到了,发送方收到这个之后,就明白了,就把窗口向右滑动两个。这里有一个问题,那就是累计确认的话,什么时候选择回ack呢,如果收到的帧一直都是对的,迟迟不回,发送方岂不是会超时。

2、丢数据

看这个例子,发送方发送0、1、2,接收方收到0、1后回了ack1,发送方滑动两个窗口,接着发3号帧,可是这时2号帧丢了,接收方收到3号帧后,发现这不是我要的啊,我要的是2号帧,他就丢弃,并且回一个ack1,表示并没有受到2号帧。 这是有一个问题,那就是只有收到帧校验和对的时候,才会回ack,例如这里3号帧如果校验和不对,那就不会回ack1,因为校验和不对时,序号就没有意义了,有可能是错的。然后继续,发送方没有收到ack2和ack3,2、3号帧就会依次超时,并重传。

3、ack丢失

考虑一个极端情况,发送方发送0、1、2号帧,接收方都正确收到并滑动了窗口,并且回了ack,可是ack全丢了,这时接收方窗口在等3号帧,发送方0号帧超时重传,接收方收到后发现不是我要的帧,就会丢掉,回一个我正在等的帧序号的前一个序号,比如这里等的是3号帧,回的ack就是ack2。这时发送方收到ack2后,就知道前三个帧都收到了,就会往右滑三次窗口。

4、窗口大小问题

窗口大小和序号的二进制位数有关,对于n比特位的序号来说,发送窗口和接收窗口的大小的和需要小于等于2的n次方。对于GBN协议来说,接收窗口大小是1,那发送窗口大小就要小于等于2的n次方减一。

如何考虑窗口大小的问题呢,只需要考虑一种极限情况,那就是发送窗口把所有帧全发出去了,接收方的ack全丢了,这时候接收窗口不能和发送窗口有重叠,有重叠就有问题。

看这样一个例子

这里n=2,按照原理,发送窗口最大是3,考虑发送和窗口是4的情况,也就是右边这张图,发送方发了0、1、2、3号帧,接收方全部正确收到并回了ack,可是全丢了,这时接收方在等待新的0号帧,可是这时发送方重传了上一次的0号帧,而接收方收到后,会误以为这时新的0号帧,那么就出错了。

5、问题

问题就在于这个go back n,可能发送方发了8个帧,除了第二帧别的都对了,可这样发送方还是得重传2号帧以及他之后的所有帧,这样效率太低了。

六、Selective Repeat(选择重传) ARQ

选择重传其实就是上一个GBN得改进,把接收方窗口扩大了,遵循的窗口大小原则还是一样

 

Wt是发送窗口大小,Wr是接收窗口大小,第一条的原因和上一个协议一样,第二条的原因是接收窗口的大小大于发送窗口是没有意义的。

这里涉及一个ack timer的问题,接收方收到数据后,会设置一个timer,等待高层的数据,看能不能稍待确认过去,如果timer过了还没有高层的数据,那么就会发送ack。这里这个timer的时间需要考虑,发送方发送数据过来,接收方设置timer,timer超时回ack,这是三段时间,发送方发过来数据的时间加上ack回去的时间是一个RTT,也就是说,RTT加上timer必须要小于发送方超时重传的timer。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
模仿数据链路层的gobackn协议 /*该协议是搭载ack的回退n步协议*/ #include #include "protocol.h" #define max_seq 7 #define flag 126 #define ESC 100 #define wait_time 2700 //发送计时器等待的时间 #define ack_wait_time 280 static int phl_ready = 0; unsigned char buf[max_seq+1][270]; unsigned char ack[8]; //发送空的ack帧 unsigned char in_buf[600], last_buf[520];//接收时的缓冲区;去掉冗余之后的缓冲区,为防备因误码两帧合并为一帧而定义了很大一个数组 int nbuffered=0; //发送的帧数 int buf_size[max_seq+1]; //记下以发送各帧的帧长 int next_frame_to_send=0; int frame_in_phl=0; //用于成帧 int frame_expected=0; int ack_expected=0; int between(int a,int b,int c) { if( ((a<=b)&&(b<c)) || ((c<a)&&(a<=b)) || ((b<c)&&(c<a)) ) return 1; else return 0; } //判断帧尾,防止出现误判esc esc flag为数据的情况 int end_flag(int in_len) { int count=0; int i; if(in_len=0;i--)//记录flag前的esc数目 count++; return count%2; //若flag前的esc为偶数,则为帧尾 }//成帧函数--数据帧 void send_frame(char *my_buf,int len) { int n; buf[frame_in_phl][0]=(frame_expected+max_seq)%(max_seq+1); //ack buf[frame_in_phl][1]=frame_in_phl; //发送帧的帧号 for(n=0;n<len;n++) buf[frame_in_phl][n+2]=my_buf[n]; //将处理过的新帧赋值到缓冲区中 len=len+2; *(unsigned int *)(buf[frame_in_phl]+len) = crc32(buf[frame_in_phl],len); //在原始帧的基础上加检验和 buf_size[frame_in_phl]=len+4; //记录当前帧的长度,包括3个帧头,4个检验和 nbuffered=nbuffered+1; //缓冲区占用数加一 frame_in_phl=(frame_in_phl+1)%(max_seq+1); } //成帧函数--ack帧 void send_ack() //ack帧的处理 { ack[0]=(frame_expected+max_seq)%(max_seq+1); ack[1]=max_seq+10; //ack帧的序号位,使ack[1]==frame_expected恒不成立 *(unsigned int *)(ack+2) = crc32(ack,2); //在原始帧的基础上加检验和 } //主函数 int main(int argc, char **argv) { int event, arg, n , m , i , j , len = 0 ,in_len = 0; unsigned char my_buf[260]; int phl_wait=0; //在物理层中还没有被发送的帧 protocol_init(argc, argv); enable_network_layer(); for (;;) { event = wait_for_event(&arg); switch (event) { case NETWORK_LAYER_READY:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值