计算机网络滑动窗口实验报告班级:2012211306学号:2012211249姓名:查凯文一.实验目的通过上机编程模拟滑动窗口协议中的协议6——选择性重传协议,熟悉和掌握协议6的基本概念、基本原理以及实现方法和过程,并与协议5进行对比,加深对滑动窗口协议的理解和认识。
二.实验内容在Linux、WindowsNT下编程模拟实现滑动窗口协议的1bit滑动窗口协议,需要分别实现发送方功能与接收方功能。
三.实验说明a)窗口机制滑动窗口协议的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口;同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口。
发送窗口和接收窗口的序号的上下界不一定要一样,甚至大小也可以不同。
不同的滑动窗口协议窗口大小一般不同。
发送方窗口内的序列号代表了那些已经被发送,但是还没有被确认的帧,或者是那些可以被发送的帧。
分析:①初始态,发送方没有帧发出,发送窗口前后沿相重合。
接收方0号窗口打开,等待接收0号帧;②发送方打开0号窗口,表示已发出0帧但尚确认返回信息。
此时接收窗口状态不变;③发送方打开0、1号窗口,表示0、1号帧均在等待确认之列。
至此,发送方打开的窗口数已达规定限度,在未收到新的确认返回帧之前,发送方将暂停发送新的数据帧。
接收窗口此时状态仍未变;④接收方已收到0号帧,0号窗口关闭,1号窗口打开,表示准备接收1号帧。
此时发送窗口状态不变;⑤发送方收到接收方发来的0号帧确认返回信息,关闭0号窗口,表示从重发表中删除0号帧。
此时接收窗口状态仍不变;⑥发送方继续发送2号帧,2号窗口打开,表示2号帧也纳入待确认之列。
至此,发送方打开的窗口又已达规定限度,在未收到新的确认返回帧之前,发送方将暂停发送新的数据帧,此时接收窗口状态仍不变;⑦接收方已收到1号帧,1号窗口关闭,2号窗口打开,表示准备接收2号帧。
此时发送窗口状态不变;⑧发送方收到接收方发来的1号帧收毕的确认信息,关闭1号窗口,表示从重发表中删除1号帧。
此时接收窗口状态仍不变。
b)选择重传协议在后退n协议中,接收方若发现错误帧就不再接收后续的帧,即使是正确到达的帧,这显然是一种浪费。
另一种效率更高的策略是当接收方发现某帧出错后,其后继续送来的正确的帧虽然不能立即递交给接收方的高层,但接收方仍可收下来,存放在一个缓冲区中,同时要求发送方重新传送出错的那一帧。
一旦收到重新传来的帧后,就可以原已存于缓冲区中的其余帧一并按正确的顺序递交高层。
这种方法称为选择重发(SELECTICE REPEAT),其工作过程如图所示。
显然,选择重发减少了浪费,但要求接收方有足够大的缓冲区空间。
四.实验结果一、性能测试表序号命令 说明运行时间(秒) 效率(%) 备注A B 1 datalink au datalink bu 无误码信道数据传输1200 51.59 96.972 datalink adatalink b 站点A 分组层平缓方式发出数据,站点B 周期性交替“发送100秒,停发100秒”120048.87 87.523 datalink afu datalink bfu 无误码信道,站点A 和站点B 的分组层都洪水式产生分组1200 96.97 96.974 datalink afdatalink bf站点A/B 的分组层都洪水式产生分组1200 87.42 87.32 5 datalink af –ber 1e-4 datalink bf –ber 1e-4 站点A/B 的分组层都洪水式产生分组,线路误码率设为10-4120096.97 96.97二、运行效果图1.a/b2.au/bu3.af/bf4.auf/buf5.af -ber le-4/bf -ber le -4五.源程序#include <stdio.h>#include <string.h>#include "protocol.h"#include "datalink.h"/* 协议参数*/#define MAX_SEQ 31#define NR_BUFS ((MAX_SEQ + 1) / 2)//避免窗口重叠#define DATA_TIMER 3000/* ms */#define ACK_TIMER 1500 //ms */# define PRINT 0//是否输出分组内容typedef unsigned char seq_nr;/* 帧参数*/typedef struct{seq_nr kind; //帧的类型有ack、nak、data三种seq_nr ack; //ack序号seq_nr seq; //帧的序号seq_nr data[PKT_LEN]; //分组类容unsigned int padding; //填充位,是干嘛的?}FRAME;//发送方数据结构seq_nr ack_expected = 0;seq_nr next_frame_to_send = 0;seq_nr out_buffer[NR_BUFS][PKT_LEN];seq_nr nbuffered = 0;//接收方数据seq_nr frame_expected = 0;seq_nr unable_to_receive = NR_BUFS;seq_nr in_buffer[NR_BUFS][PKT_LEN];seq_nr arrived[NR_BUFS];int physical_ready = 0 ;int nak_enable = 0;/*滑动窗口*/static int inc(int x){x++;if(x == MAX_SEQ+1)x = 0;return x;}/* 判断是否在窗口内*/static int between(seq_nr a, seq_nr b, seq_nr c){return (((a <= b) && (b < c)) || ((c < a)&&(a <= b)) || ((b < c)&&(c < a))); }/* 交给网络层*/static void put_frame(seq_nr * frame, int len){*(unsigned int *)(frame + len) = crc32(frame, len);send_frame(frame, len+4);physical_ready = 0;}/* 向发送数据帧*/static void send_data_frame(seq_nr frame_nr) //{FRAME s;s.kind = FRAME_DATA;s.seq = frame_nr;s.ack = ((frame_expected + MAX_SEQ)%(1 + MAX_SEQ));memcpy(s.data, out_buffer[frame_nr%NR_BUFS], PKT_LEN);put_frame((seq_nr*)&s, 3 + PKT_LEN);start_timer(frame_nr, DATA_TIMER);}/* 向物理层发送确认帧*/static void send_ack_frame(void){FRAME s;s.kind = FRAME_ACK;s.ack = ((frame_expected + MAX_SEQ)%(1 + MAX_SEQ));put_frame((seq_nr*)&s, 2);}/* 向物理层发送否定确认帧*/static void send_nak_frame(void){FRAME s;s.kind = FRAME_NAK;s.ack = (frame_expected + MAX_SEQ)%(1 + MAX_SEQ);put_frame((seq_nr *)&s,2);}//***********************************************************主函数***************************************************************int main(int argc, char **argv){int event;FRAME f;int len = 0;int i;int arg;//初始化protocol_init(argc, argv); /*协议初始化*/disable_network_layer();for(i = 0; i < NR_BUFS; i++)arrived[i] = 0;for(;;){event = wait_for_event(&arg);switch (event){case NETWORK_LAYER_READY://网络层有分组要发送get_packet(out_buffer[next_frame_to_send%NR_BUFS]);#if PRINTlog_printf("从网络层收到分组%d\n",*(short *)out_buffer[next_frame_to_send%NR_BUFS]);#endifnbuffered++;send_data_frame(next_frame_to_send);#if PRINTlog_printf("提交到物理层数据帧%d\n",*(short *)out_buffer[next_frame_to_send%NR_BUFS]);#endifstop_ack_timer();next_frame_to_send = inc(next_frame_to_send);break;case PHYSICAL_LAYER_READY://物理层准备好了physical_ready = 1;break;case FRAME_RECEIVED://一个数据帧到达len = recv_frame((seq_nr *)&f,sizeof(f));#if PRINTlog_printf("收到数据帧%d\n",*(short *)f.data);log_printf("ack_expected %d, next_frame_to_send %d, frame_expectted %d \n",ack_expected,next_frame_to_send,frame_expected);log_printf("f.seq %d f.ack %d\n",f.seq, f.ack);#endifif( crc32((unsigned char *)&f, len) != 0){#if PRINTlog_printf("CRC ERROR!%d sequence %d\n",*(short *)f.data,f.seq);#endifif(nak_enable == 1){send_nak_frame();#if PRINTlog_printf("发送NAK帧,期望收到%d\n",*(short*)f.data);#endifstop_ack_timer();nak_enable = 0;}break;}if(f.kind == FRAME_ACK)#if PRINTlog_printf("收到ACK应答!\n");#endifif(f.kind == FRAME_NAK){#if PRINTlog_printf("从物理层收到NAK帧!,对方收到了%d\n",f.ack);log_printf("ack_expected %d, next_frame_to_send %d\n",ack_expected,next_frame_to_send);#endifif(between(ack_expected, inc(f.ack),next_frame_to_send)){send_data_frame(inc(f.ack));stop_ack_timer();}break;}if(f.kind == FRAME_DATA){#if PRINTlog_printf("收到数据帧%d\n",*(short *)f.data);#endifif(f.seq != frame_expected && nak_enable == 1){send_nak_frame();stop_ack_timer();nak_enable = 0;}elsestart_ack_timer(ACK_TIMER);if(between(frame_expected, f.seq, unable_to_receive) && arrived[f.seq%NR_BUFS] == 0){memcpy(in_buffer[f.seq%NR_BUFS],f.data, PKT_LEN);arrived[f.seq%NR_BUFS] = 1;while(arrived[frame_expected%NR_BUFS] == 1){put_packet(in_buffer[frame_expected%NR_BUFS],PKT_LEN);#if PRINTlog_printf("提交到网络层%d\n",*(short *)in_buffer[frame_expected%NR_BUFS]);#endifarrived[frame_expected%NR_BUFS] = 0;frame_expected = inc(frame_expected);unable_to_receive = inc(unable_to_receive);start_ack_timer(ACK_TIMER);nak_enable = 1;}}}while(between(ack_expected,f.ack,next_frame_to_send)){#if PRINTlog_printf("nbuffered %d, ack_expected\n",nbuffered,ack_expected);#endifstop_timer(ack_expected);ack_expected = inc(ack_expected);nbuffered --;}break;case DATA_TIMEOUT://TIMER超时#if PRINTlog_printf("超时重传\n");#endifsend_data_frame(ack_expected);stop_ack_timer();break;case ACK_TIMEOUT://ack超时send_ack_frame();break;}if(nbuffered < NR_BUFS && physical_ready)enable_network_layer();elsedisable_network_layer();}return 0;}六.总结通过自己编写一个协议,自己对协议本身的理解也加深了。