您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > 滑动窗口协议模拟程序
课程设计5---滑动窗口协议模拟程序的设计与实现姓名:学号:一、目标任务(1)了解网络协议编程的基本知识;(2)了解滑动窗口协议的工作机制;(3)使用编程语言编写一个滑动窗口协议的模拟程序,按要求实现程序。二、编程语言C语言三、滑动窗口协议介绍3.1滑动窗口协议工作原理TCP协议在工作时,如果发送端的TCP协议软件每传输一个数据分组后,必须等待接收端的确认才能够发送下一个分组,由于网络传输的时延,将有大量时间被用于等待确认,导致传输效率低下。为此TCP在进行数据传输时使用了滑动窗口机制。TCP滑动窗口用来暂存两台计算机间要传送的数据分组。每台运行TCP协议的计算机有两个滑动窗口:一个用于数据发送,另一个用于数据接收。发送端待发数据分组在缓冲区排队等待送出。被滑动窗口框入的分组,是可以在未收到接收确认的情况下最多送出的部分。滑动窗口左端标志X的分组,是已经被接收端确认收到的分组。随着新的确认到来,窗口不断向右滑动。TCP协议软件依靠滑动窗口机制解决传输效率和流量控制问题。它可以在收到确认信息之前发送多个数据分组。这种机制使得网络通信处于忙碌状态,提高了整个网络的吞吐率,它还解决了端到端的通信流量控制问题,允许接收端在拥有容纳足够数据的缓冲之前对传输进行限制。在实际运行中,TCP滑动窗口的大小是可以随时调整的。收发端TCP协议软件在进行分组确认通信时,还交换滑动窗口控制信息,使得双方滑动窗口大小可以根据需要动态变化,达到在提高数据传输效率的同时,防止拥塞的发生。称窗口左边沿向右边沿靠近为窗口合拢,这种现象发生在数据被发送和确认时。当窗口右边沿向右移动时将允许发送更多的数据,称之为窗口张开。这种现象发生在另一端的接收进程读取已经确认的数据并释放了TCP的接收缓存时。当右边沿向左移动时,称为窗口收缩。HostRequirementsRFC强烈建议不要使用这种方式。但TCP必须能够在某一端产生这种情况时进行处理。如果左边沿到达右边沿,则称其为一个零窗口。3.2滑动窗口算法滑动窗口算法工作过程如下:首先,发送方为每1帧赋一个序号(sequencenumber),记作SeqNum。现在,我们忽略SeqNum是由有限大小的头部字段实现的事实,而假设它能无限增大。发送方维护3个变量:发送窗口大小(sendwindowsize),记作SWS,给出发送方能够发送但未确认的帧数的上界;LAR表示最近收到的确认帧(lastacknowledgementreceived)的序号;LFS表示最近发送的帧(lastframesent)的序号,发送方还维持如下的不变式:LAR-LFS≤SWS。图3-1滑动窗口算法的时间线当一个确认到达时,发送方向右移动LAR,从而允许发送方发送另一帧。同时,发送方为所发的每个帧设置一个定时器,如果定时器在ACK到达之前超时,则重发此帧。注意:发送方必须存储最多SWS个帧,因为在它们得到确认之前必须准备重发。接收方维护下面3个变量:接收窗口大小(receivewindowsize),记为RWS,给出接收方所能接收的无序帧数目的上界;LAF表示可接收帧(largestacceptableframe)的序号;LFR表示最近收到的帧(lastframereceived)的序号。接收方也维持如下不变式:LFS-LAR≤SWS图3-2接收方的滑动窗口当一个具有顺序号SeqNum的帧到达时,接收方采取如下行动:如果SeqNum≤LFR或SeqNumLAF,那么帧不在接收窗口内,于是被丢弃;如果LFR<SeqNum≤LAF,那么帧在接收窗口内,于是被接收。现在接收方需要决定是否发送一个ACK。设SeqNumToACK表示未被确认帧的最大序号,则序号小于或等于SeqNumToACK的帧都已收到。即使已经收到更高序号的分组,接收方仍确认SeqNumToACK的接收。这种确认被称为是累积的(cumulative)。然后它设置LFA=SeqNumToACK,并调整LFA=LFR+RWS。图3-3接收方的滑动窗口窗口协议算法有三个功能:在不可靠链路上可靠地传输帧保持帧的传输顺序支持流量控制四、设计方案及分析4.1窗口机制总体设计及分析图4-1发送方和接收方状态示意图LFRLFR设计分析:(1)初始态,发送方没有帧发出,发送窗口前后沿相重合。接收方0号窗口打开,等待接收0号帧;(2)发送方打开0号窗口,表示已发出0帧但尚未确认返回信息。此时接收窗口状态不变;(3)发送方打开0、1号窗口,表示0、1号帧均在等待确认之列。至此,发送方打开的窗口数已达规定限度,在未收到新的确认返回帧之前,发送方将暂停发送新的数据帧。接收窗口此时状态仍未变;(4)接收方已收到0号帧,0号窗口关闭,1号窗口打开,表示准备接收1号帧。此时发送窗口状态不变;(5)发送方收到接收方发来的0号帧确认返回信息,关闭0号窗口,表示从重发表中删除0号帧。此时接收窗口状态仍不变;(6)发送方继续发送2号帧,2号窗口打开,表示2号帧也纳入待确认之列。至此,发送方打开的窗口又已达规定限度,在未收到新的确认返回帧之前,发送方将暂停发送新的数据帧,此时接收窗口状态仍不变;(7)接收方已收到1号帧,1号窗口关闭,2号窗口打开,表示准备接收2号帧。此时发送窗口状态不变;(8)发送方收到接收方发来的1号帧收毕的确认信息,关闭1号窗口,表示从重发表中删除1号帧。此时接收窗口状态仍不变。4.2协议选择及分析在设计过程中,我主要运用了选择重传协议,该协议能很好地弥补了1比特滑动窗口协议和后退n协议的缺点,是比较完善的滑动窗口协议。在选择重传协议中,当接收方发现某帧出错后,其后继续送来的正确的帧虽然不能立即递交给接收方的高层,但接收方仍可收下来,存放在一个缓冲区中,同时要求发送方重新传送出错的那一帧。一旦收到重新传来的帧后,就可以原已存于缓冲区中的其余帧一并按正确的顺序递交高层。这种方法称为选择重发(SELECTICEREPEAT),其工作过程如图所示。显然,选择重发减少了浪费,但要求接收方有足够大的缓冲区空间。图4-2选择重传协议原理图4.3发送方与接收方设计流程由于我设计的程序为模拟程序,因此我把发送方和接收方集合在同一版面上。它们各自的功能同时在同一版面上实现及显示。在程序实现后,我们可以通过在同一版面根据提示输入相关信息,即可得到模拟过程。虽然只有一个版面,但是发送方和接收方的功能是清晰的、相对齐全的。发送方和接收方的设计流程如下:图4-3发送方与接收方设计流程五、关键代码(1)发送方程序:本程序设有四个变量:一是窗口大小变量,二是第一帧序列号变量,三是最近发送的帧变量,最后一个是最近收到的确认帧变量。swpstate1.head=NULL;//变量初始值为空swpstate1.sendq=sendq_rear=(structsendq_slot*)malloc(sizeof(structsendq_slot);if(!swpstate1.sendq)exit(1);sendq_rear-next=NULL;printf(请输入窗口大小:);scanf(%ld,&swpstate1.sws);//输入窗口大小swpstate1.rws=swpstate1.sws;//把窗口大小的值赋给变量if(swpstate1.sws0){printf(请输入第一帧的序列号:);scanf(%ld,&swpstate1.hdr.seqnum);//输入第一帧序列号}swpstate1.nfe=swpstate1.hdr.seqnum;//把第一帧的值放进缓冲池内sendp=(structsendq_slot*)malloc(sizeof(structsendq_slot));if(!sendp)exit(1);sendp-msg=swpstate1.hdr.seqnum;sendp-timeout=1;sendp-next=NULL;sendq_rear-next=sendp;sendq_rear=sendp;--swpstate1.sws;swpstate1.lfs=swpstate1.hdr.seqnum;//最近发送的帧取值swpstate1.lar=swpstate1.hdr.seqnum;//最近收到的确认帧取值do{while(swpstate1.sws0)//当窗口大小大于0时,执行以下的循环{sendp=(structsendq_slot*)malloc(sizeof(structsendq_slot));if(!sendp)exit(1);sendp-msg=swpstate1.lfs+1;//如果输入的帧序号大于之前帧序号,那么窗口向前滑动sendp-timeout=1;//时延为1sendp-next=NULL;sendq_rear-next=sendp;sendq_rear=sendp;--swpstate1.sws;++swpstate1.lfs;}swpstate1.hdr.acknum=0;//ACK清空swpstate1.hdr.flags=0;//存储缓冲池清空printf(最近收到的ACK的帧序号:%ld\n,swpstate1.lar);//输出最近收到的ACK帧序号printf(最近发送的帧序号(发送新帧后):%ld\n,swpstate1.lfs);//输出最近发送帧序号(2)接收方程序:①接收方的接收原则从总体上看是先判断输入的数据帧是否在接收范围之内,若是,则继续判断是否符合其他接收条件;若不是,则马上丢弃该数据帧,不再进行其他条件的判断。structsendq_slot*sendq_rear,*sendp,*p3,*p4;//设定变量structrecvq_slot*recvp,*recvq_rear,*p1,*p2;if(swpstate1.hdr.flags==0)//上次输入的数据帧被放置在缓存区,输入区被清空{do//如果继续接收数据帧则实施下面循环{printf(请输入收到的数据帧号:);scanf(%ld,&a);if(a=swpstate1.nfe&&a=swpstate1.lfs)//判断数据帧应被接收或缓存{if(swpstate1.head==NULL){recvp=recvq_rear=(structrecvq_slot*)malloc(sizeof(structrecvq_slot));recvp-next=NULL;swpstate1.head=recvp;}elseif(swpstate1.head!=NULL){recvp=(structrecvq_slot*)malloc(sizeof(structrecvq_slot));recvp-next=NULL;recvq_rear-next=recvp;recvq_rear=recvp;}}else{printf(所输数据不在接收窗口内!);break;//跳出该循环}②若输入数据帧在接收范围内则继续判断并进行以下循环。recvp-msg=a;if(recvp-msg==swpstate1.nfe)//是否放入缓存判断recvp-received=1;elserecvp-received=0;--swpstate1.rws;if(recvp-received==1)//数据帧被接收,则进行下面语句{a=a-1;do{a=a+1;if(swpstate1.head==NULL)break;p1=swpstate1.head;flag=0;while((a!=p1-msg)&&(p1-next!=NULL)){p2=p1;p1=p1-next;}if(a==p1-msg){flag=1;if(p1==swpstate1.head)swpstate1.head=swpstate1.head-next;elsep2-next=p1-next;swpstate1.nfe=a+1;swpstate1.hdr.acknum=a+1;
本文标题:滑动窗口协议模拟程序
链接地址:https://www.777doc.com/doc-5928547 .html