课程设计报告-滑动窗口协议仿真.doc

上传人:知****量 文档编号:12991874 上传时间:2022-04-27 格式:DOC 页数:31 大小:407KB
返回 下载 相关 举报
课程设计报告-滑动窗口协议仿真.doc_第1页
第1页 / 共31页
课程设计报告-滑动窗口协议仿真.doc_第2页
第2页 / 共31页
点击查看更多>>
资源描述

《课程设计报告-滑动窗口协议仿真.doc》由会员分享,可在线阅读,更多相关《课程设计报告-滑动窗口协议仿真.doc(31页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、. .XX学院课程设计报告课程名称: 计算机网络 设计题目: 滑动窗口协议仿真 系 别: 计算机与信息工程学院 专 业: 计算机科学与技术 组 别:第五组起止日期:2021年11月24日2021年12月7日指导教师:赵国柱计算机与信息工程学院二一一年制课程设计题目滑动窗口协议仿真组长赵育坤学号2021220215班级计专1班系别计算机与信息工程学院专业计算机科学与技术组员闫婷、X侠、余静、于东锋、X飞、赵育坤指导教师赵国柱课程设计目的掌握滑动窗口协议的根本原理,并能够用所学计算机高级语言进展编程模拟课程设计所需环境开发环境:VC+ 运行环境:Windows 操作系统课程设计任务要求1程序按照滑

2、动窗口协议实现端对端的数据传送。包括协议的各种策略,如包丧失、停等应答、超时等都应有所仿真实现2显示数据传送过程中的各项具体数据。双方帧的个数变化,帧序号,发送和承受速度,暂停或重传提示等课程设计工作进度方案序号起止日期工 作 容分工情况111月24号11月27号了解工作要求,明确分工内容,网上查阅相关资料所有组员共同参与211月28号11月30号sender队列模块的编写由闫婷完成312月1号12月4号sender主函数的编写由赵育坤、X飞完成411月28号11月30号receiver队列模块的编写由X侠完成512月1号12月4号receiver主函数的编写由余静、于东锋完成612月5号12

3、月7号最后汇总,调试由赵育坤、于东锋完成指导教师签字: 年 月 日教研室审核意见:教研室主任签字: 年 月 日课程设计任务书一. 引言二. 根本原理2.1窗口机制2.2 1bit滑动窗口协议2.3 后退N协议2.4 选择重传协议2.5 流量控制三. 需求分析3.1 课程设计题目3.2 开发环境3.3运行环境3.4 课程设计任务及要求3.5 界面要求3.6 网络接口要求四. 详细设计4.1 构造体的定义4.2 发送方的主要函数4.3 承受方的主要函数五.源代码5.1 发送方的主要代码5.2 接收方的主要代码六. 调试与操作说明 致谢参考文献 课程设计的主要内容1.引言早期的网络通信中,通信双方不

4、会考虑网络的拥挤情况直接发送数据。由于大家不知道网络拥塞状况,一起发送数据,导致中间结点阻塞掉包,谁也发不了数据。在数据传输过程中,我们总是希望数据传输的更快一些,但如果发送方把数据发送的过快,接收方就可能来不及接收,这就造成数据的丧失。因此就有了滑动窗口机制来解决这些问题。早期我们使用的是1bit滑动窗口协议,一次只发送一个帧,等收到ack确认才发下一个帧,这样对信道的利用率太低了。因此提出了一种采用累积确认的连续ARQ协议,接收方不必对收到的帧逐个发送ack确认,而是收到几个帧后,对按序到达的最后一个帧发送ack确认。同1bit滑动窗口协议相比,大大减少了ack数量,并消除了延迟ack对传

5、输效率的影响。但是,这会产生一个新的问题,如果发送方发送了5个帧,而中间的第3个帧丧失了。这时接收方只能对前2个帧发出确认。发送方无法知道后面三个帧的下落,只好把后面的3个帧再重传一次,这就是回退N协议。为了解决这个问题,又提出了选择重传协议。当接收方发现某帧出错后,继续承受后面送来的正确的帧,只是不交付它们,存放在自己的缓冲区中,并且要求发送方重传出错的那一帧。一旦收到重传来的帧后,就可以将存于缓冲区中的其余帧一并按正确的顺序递交给主机。2.根本原理2.1 窗口机制滑动窗口协议的根本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口;同时,接收方也维持了一个连续的允

6、许接收的帧的序号,称为接收窗口。发送窗口和接收窗口的序号的上下界不一定要一样,甚至大小也可以不同。不同的滑动窗口协议窗口大小一般不同。发送方窗口内的序号代表了那些已经被发送,但是还没有被确认的帧,或者是那些可以被发送的帧。承受方为其窗口内的每一个序号保存了一个缓冲区。与每个缓冲区相关联的还有一位,用来指明该缓冲区是满的还是空的。假设从滑动窗口的观点来统一对待1比特滑动窗口、后退n及选择重传三种协议,它们的差异仅在于各自窗口尺寸的大小不同而已。1比特滑动窗口协议:发送窗口=1,接收窗口=1;后退N协议:发送窗口1,接收窗口=1;选择重传协议:发送窗口1,接收窗口1。2.21bit滑动窗口协议当发

7、送窗口和接收窗口的大小固定为1时,滑动窗口协议退化为停等协议stopandwait。该协议规定发送方每发送一帧后就要停下来,等待接收方已正确接收确实认acknowledgement返回后才能继续发送下一帧。由于接收方需要判断接收到的帧是新发的帧还是重新发送的帧,因此发送方要为每一个帧加一个序号。由于停等协议规定只有一帧完全发送成功后才能发送新的帧,因而只用一比特来编号就够了。其发送方和接收方运行的流程图如下图。2.3 后退N协议由于停等协议要为每一个帧进展确认后才继续发送下一帧,大大降低了信道利用率,因此又提出了后退n协议。后退n协议中,发送方在发完一个数据帧后,不停下来等待应答帧,而是连续发

8、送假设干个数据帧,即使在连续发送过程中收到了接收方发来的应答帧,也可以继续发送。且发送方在每发送完一个数据帧时都要设置超时定时器。只要在所设置的超时时间内仍收到确认帧,就要重发相应的数据帧。如:当发送方发送了N个帧后,假设发现该N帧的前一个帧在计时器超时后仍未返回其确认信息,那么该帧被判为出错或丧失,此时发送方就不得不重新发送出错帧及其后的N帧。从这里不难看出,后退n协议一方面因连续发送数据帧而提高了效率,但另一方面,在重传时又必须把原来已正确传送过的数据帧进展重传仅因这些数据帧之前有一个数据帧出了错,这种做法又使传送效率降低。由此可见,假设传输信道的传输质量很差因而误码率较大时,连续测协议不

9、一定优于停顿等待协议。此协议中的发送窗口的大小为k,接收窗口仍是1。2.4 选择重传协议在后退n协议中,接收方假设发现错误帧就不再接收后续的帧,即使是正确到达的帧,这显然是一种浪费。另一种效率更高的策略是当接收方发现某帧出错后,其后继续送来的正确的帧虽然不能立即递交给接收方的高层,但接收方仍可收下来,存放在一个缓冲区中,同时要求发送方重新传送出错的那一帧。一旦收到重新传来的帧后,就可以原已存于缓冲区中的其余帧一并按正确的顺序递交高层。这种方法称为选择重发(SELECTICE REPEAT),其工作过程如下图。显然,选择重发减少了浪费,但要求接收方有足够大的缓冲区空间。2.5 流量控制TCP的特

10、点之一是提供体积可变的滑动窗口机制,支持端到端的流量控制。TCP的窗口以字节为单位进展调整,以适应接收方的处理能力。处理过程如下: 1TCP连接阶段,双方协商窗口尺寸,同时接收方预留数据缓存区; 2发送方根据协商的结果,发送符合窗口尺寸的数据字节流,并等待对方确实认; 3发送方根据确认信息,改变窗口的尺寸,增加或者减少发送未得到确认的字节流中的字节数。调整过程包括:如果出现发送拥塞,发送窗口缩小为原来的一半,同时将超时重传的时间间隔扩大一倍。4滑动窗口机制为端到端设备间的数据传输提供了可靠的流量控制机制。然而,它只能在源端设备和目的端设备起作用,当网络中间设备例如路由器等发生拥塞时,滑动窗口机

11、制将不起作用。3.需求分析3.1 课程设计题目:滑动窗口协议仿真3.2开发环境:Visual C+ 6.03.3运行环境:Windows 操作系统3.4课程设计任务及要求: 1程序按照滑动窗口协议实现端对端的数据传送。包括协议的各种策略,如包丧失、停等应答、超时等都应有所仿真实现。 2显示数据传送过程中的各项具体数据。双方帧的个数变化,帧序号,发送和承受速度,暂停或重传提示等。3.5 界面要求:此次课程设计要求的所有功能应可视,我们组主要是用VC+编写的,运行在DOS环境下,观察发送方sender发送数据包到接收方receive时。界面应显示出双方帧个数的变化,帧序号,发送和承受速度,暂停或重

12、传提示等,界面中必须动态显示数据帧的发送和承受情况,包括在相应的窗口详细显示相应的ACK和其他收发数据帧后发出的消息,以说明模拟协议的正确运作过程。在各种情况下,承受方和发送方窗口应实时显示帧的发送和承受情况,包括序号,时间戳,内容等。以及窗口的填充和清空情况。3.6 网络接口要求:两台机器或是一台机器中两个独立的线程模拟发送方与承受方,接收数据的端口初始应为监听状态。发送方向承受方发起连接,成功后开场发送数据。4.概要设计4.1 构造体定义如下:typedef enum data = 1,ack,nak,tout frame_kind; /帧类型typedef struct frame_he

13、ad frame_kind kind; /帧类型 unsigned int seq; /序列号 unsigned int ack; /确认号 unsigned char dataMAX_LENGTH; /数据Head;typedef struct frame frame_head head; /帧头 unsigned int size; /数据的大小 Frame; typedef struct framenode /队列节点类型 frame head_data; struct framenode *next; Framenode;typedef struct Framenode *front;

14、 /队头指针 Framenode *rear; /队尾指针 LinkQueue;4.2发送方的主要函数实现:函数名:void InitLine(LinkQueue *q);功 能:初始化队列。函数名:void GetFrameFromHost(LinkQueue *q);功 能:从主机取数据帧,由于实验需要,假设主机有足够多的数据帧要发送。void DeLine(LinkQueue *q);功 能:数据帧发送完毕收到确认帧后,删除发送的数据帧队头。函数名:int QueueEmpty(LinkQueue *q);功 能:判断队列是否为空。函数名:frame QueueFront(LinkQue

15、ue *q);功 能:取队头,首帧是准备好待发送的帧。函数名:int QueueLen(LinkQueue *q);功 能:计算队列长度。函数名:DWORD WINAPI ReceiveFun(LPVOID pArg);功 能:发送线程调用的函数,pArg参数存接收帧指针。函数名:void main();功 能:发送方主函数,首先和接收方本机127.0.0.1建立socket连接并初始化发送队列。然后重复下面的步骤:1从主机取数据帧;2发送数据帧,含超时重发接收方未收到或未收到接收方ack和错误重发收到接收方nak;3设置超时计时器,这里是5秒;4等待确认,调用CreateThread()函数

16、创立一个线程,超时那么调用TerminateThread()函数完毕线程并再次发送数据帧。收到数据帧那么做后续处理;5收到否认帧nak那么再次发送数据帧,收到确认帧ack那么发送下一个数据帧;6如果发送的测试时间到达20秒,那么提示是否继续测试,按q或Q退出测试。4.3接收方的主要函数实现:函数名:void InitLine(LinkQueue *q);功 能:初始化队列。函数名:void GetFrameFromHost(LinkQueue *q);功 能:准备好接收帧的缓冲池,首帧是待接收的帧,尾帧是已经接收的待提交主机的帧。由于实验需要,假设数据帧送往主机是足够快的。int DeLine

17、(LinkQueue *q, frame *pf, unsigned int curw)功 能:将帧数据保存供提交主机,curw是翻开的待接收数据的窗口。函数名:int QueueEmpty(LinkQueue *q);功 能:判断队列是否为空。函数名:int QueueLen(LinkQueue *q);功 能:计算队列长度。函数名:void main();功 能:接收方主函数,首先和发送方建立socket连接并初始化初始化接收窗口。然后重复下面的步骤:1等待,接收数据帧;2校验数据帧,假定产生随机结果,20%的概率校验错误或发送方发送数据帧超时;3校验错误时,丢弃数据帧,并发送否认帧nak

18、;4如果出现接收超时假定未收到发送方发送的数据帧,那么不给发送发任何回应;5如果校验正确,首先判断是否是上一帧的重发。是上一帧的重发,那么丢弃数据帧,并发送确认帧ack;是新的数据帧,那么保存数据帧到当前接收窗口,并发送确认帧ack。6送数据帧至主机。5.源代码5.1 发送方的主要代码:void InitLine(LinkQueue *q) q-front = q-rear = NULL;int QueueEmpty(LinkQueue *q)return q-front = NULL & q-rear = NULL;frame QueueFront(LinkQueue *q) if (Que

19、ueEmpty(q) printf(队列为空!n); Sleep(SLEEPMS); exit(0); return q-front-head_data;int QueueLen(LinkQueue *q)if (QueueEmpty(q) return 0; int num = 0;Framenode *p = q-front;while(p != NULL)num+;p = p-next;return num;void GetFrameFromHost(LinkQueue *q) if(QueueLen(q) = MAXPOOL) printf(data %d 已准备好n, q-front

20、-head_data.head.seq);return;Framenode *p=(Framenode *)malloc(sizeof(Framenode);memset(p-head_data.head.data, 0, MAX_LENGTH);srand(unsigned)time(NULL);p-head_data.size = rand() % MAX_LENGTH; / 帧大小随机生成memset(p-head_data.head.data, 1, p-head_data.size);p-head_data.head.ack = -1;p-head_data.head.kind =

21、data;p-head_data.head.seq = 0;p-next =NULL;if(QueueEmpty(q)q-front = q-rear=p; / 首帧是待发送的帧elsep-head_data.head.seq = (q-rear-head_data.head.seq + 1)%MAXPOOL;q-rear-next =p;q-rear =p;printf(从主机得到:data %d,放入缓存n, p-head_data.head.seq);GetFrameFromHost(q); / 由于实验需要,假设主机有足够多的数据帧要发送void DeLine(LinkQueue *q

22、)Framenode *p = NULL;if(QueueEmpty(q)printf(队列为空!n);else p = q-front;q-front = p-next;if (q-rear = p)q-rear = NULL;printf(发送data %d, %d 成功!从缓存中删除n, p-head_data.head.seq, p-head_data.size);free(p);p = NULL;void main() printf(建立连接 . n);Begin:WORD wVersionRequested; WSADATA wsaData; /初始化socket库wVersion

23、Requested=MAKEWORD(1,1); /两个byte型合并成一个WORD型int err=WSAStartup(wVersionRequested,&wsaData);if(err!=0) Sleep(SLEEPMS); return; if ( LOBYTE( wsaData.wVersion ) != 1 | HIBYTE( wsaData.wVersion ) != 1 ) WSACleanup(); /中止Windows Sockets效劳 WSAStartup()成对使用Sleep(SLEEPMS); return; socketClient = socket(AF_IN

24、ET,SOCK_STREAM,0);/监听的套接字SOCKADDR_IN clientadd; clientadd.sin_addr.S_un.S_addr = inet_addr(127.0.0.1); clientadd.sin_family = AF_INET; clientadd.sin_port = htons(7001);/设置连接端的IP、端口if(SOCKET_ERROR=connect(socketClient,(SOCKADDR*)&clientadd,sizeof(SOCKADDR) ) /连接WSACleanup();Sleep(SLEEPMS);goto Begin;

25、char getDataRECEIVE_MAX_LENGTH;memset(getData, 0, RECEIVE_MAX_LENGTH); /清零if(recv(socketClient,getData,RECEIVE_MAX_LENGTH,0) = SOCKET_ERROR) /承受 printf(承受连接提示信息出错!n); else printf(%sn,getData); char sendDataSEND_MAX_LENGTH;memset(sendData, 0, SEND_MAX_LENGTH); strcpy(sendData, 你好接收方,我是发送方!);if( SOCKE

26、T_ERROR = send(socketClient,sendData,strlen(sendData)+1,0) ) /发送 printf(发送连接提示信息出错!n);WSACleanup();closesocket(socketClient);Sleep(SLEEPMS); return; printf(按任意键继续!n);while (!kbhit() ; /等待开场Sleep(SLEEPMS);printf(1bit滑动窗口协议:发送方,发送窗口=1n);LinkQueue QueueQ;InitLine(&QueueQ);frame packetsend; /dataframe p

27、acketreceive; / ack,nakunsigned long tick = GetTickCount(); int ret = 0;HANDLE hThread; while(1)GetFrameFromHost(&QueueQ);/从主机取数据帧memset(&packetsend, 0, sizeof(packetsend);Sleep(SLEEPMS);printf(n);packetsend = QueueFront(&QueueQ); /取数据帧ret = send(socketClient, (char *)&packetsend, sizeof(packetsend)

28、, 0);/发送dataif(ret = SOCKET_ERROR)printf(发送数据出错!n); continue; printf(发送数据帧:data %d, %dn, packetsend.head.seq, packetsend.size);const unsigned long timeOut = 5 * 1000; /设置超时计时器 5秒超时memset(&packetreceive, 0, sizeof(packetreceive);Sleep(SLEEPMS);printf(n);InitializeCriticalSection(&gCS); / 初始化临界区 hThre

29、ad=CreateThread(NULL, 0, ReceiveFun, (LPVOID)&packetreceive, 0, NULL);int r = WaitForMultipleObjects(1, &hThread, TRUE, timeOut);DeleteCriticalSection(&gCS); /与InitializeCriticalSection(&gCS);成对使用if(ret = SOCKET_ERROR | ret = SOCKET_DISCONN)printf(承受出错!Press any key to continuen); while (!kbhit() ;

30、continue; if(r = WSA_WAIT_TIMEOUT) /判断超时TerminateThread(hThread, 0); /终止线程printf(超时重传:data %d, %dn, packetsend.head.seq,packetsend.size); else if(packetsend.head.seq = packetreceive.head.ack)srand(unsigned)time(NULL);switch(rand() % 5) /假定产生随机结果,20%的概率超时case 0:printf(接收方发送回复超时(ack丧失模拟):%dn, packetse

31、nd.head.seq);printf(超时重传:data %d, %dn, packetsend.head.seq,packetsend.size);break;default:if(packetreceive.head.kind = ack) printf(承受ack帧:ack %dn, packetreceive.head.ack);DeLine(&QueueQ);else if(packetreceive.head.kind = nak)printf(承受nak帧:nak %dn, packetsend.head.seq);break;else printf(帧序号出错: %dn, p

32、acketreceive.head.ack);if(GetTickCount() - tick 20 * TIMEOUT) /设置时间20秒printf(持续时间20s. 按q退出,其他键继续n); int kbc = getch();if(kbc = q | kbc = Q)break;printf(按任意键退出!n); while (!kbhit() ; Sleep(SLEEPMS);printf(谢谢使用!n);WSACleanup();closesocket(socketClient);Sleep(SLEEPMS);DWORD WINAPI ReceiveFun(LPVOID pArg

33、) EnterCriticalSection(&gCS);/进入critical sectionframe *packetreceive = (frame *)pArg;ret = recv(socketClient, (char *)packetreceive, sizeof(*packetreceive), 0);LeaveCriticalSection(&gCS);/线程用毕,离开critical sectionreturn ret; 5.2 接收方的主要代码:void InitLine(LinkQueue *q)q-front = q-rear = NULL;int QueueEmpt

34、y(LinkQueue *q)return q-front = NULL & q-rear = NULL;frame QueueFront(LinkQueue *q)if (QueueEmpty(q) printf(队列为空!n); Sleep(SLEEPMS); exit(0); return q-front-head_data;int QueueLen(LinkQueue *q)if (QueueEmpty(q) return 0; int num = 0;Framenode *p = q-front;while(p != NULL)num+;p = p-next;return num;i

35、nt GetFrameFromHost(LinkQueue *q)if(QueueLen(q) = MAXPOOL)printf(准备承受:data %d n, q-front-head_data.head.seq);return q-front-head_data.head.seq;Framenode *p=(Framenode *)malloc(sizeof(Framenode);memset(p-head_data.head.data, 0, MAX_LENGTH);p-head_data.head.ack = -1;p-head_data.head.kind = ack;p-head_

36、data.head.seq = 0;p-next =NULL;if(QueueEmpty(q)q-front = q-rear=p; elsep-head_data.head.seq = (q-rear-head_data.head.seq + 1)%MAXPOOL;q-rear-next =p;q-rear = p;return GetFrameFromHost(q);int DeLine(LinkQueue *q, frame *pf, unsigned int curw) /假设数据帧送往主机是足够快的Framenode *p = NULL;if(curw = q-front-head_

37、data.head.seq) p = q-front;elsep = q-rear;if(p-head_data.head.ack != -1) /假定数据已经提交主机printf(向主机交付data %d, %d 成功!n, p-head_data.head.ack, p-head_data.size);memset(p-head_data.head.data, 0, MAX_LENGTH);memcpy(p-head_data.head.data, pf-head.data, pf-size); p-head_data.size = pf-size;p-head_data.head.ack

38、 = pf-head.seq; /保存发送帧序号return p-head_data.head.seq;frame QueueAnswer(LinkQueue *q, unsigned int curw)if(curw = q-front-head_data.head.seq) return q-front-head_data;elsereturn q-rear-head_data;void main()Begin: WORD wVersionRequested; WSADATA wsaData; /初始化socket库 wVersionRequested = MAKEWORD( 1, 1 )

39、; /两个byte型合并成一个WORD型 int err = WSAStartup(wVersionRequested, &wsaData );/使用sockets之前要调用一次if ( err != 0 ) Sleep(SLEEPMS); return; if ( LOBYTE( wsaData.wVersion ) != 1 | HIBYTE( wsaData.wVersion ) != 1 ) WSACleanup();/中止Windows Sockets效劳 WSAStartup()成对使用Sleep(SLEEPMS); return; SOCKET socksrv = socket(

40、AF_INET,SOCK_STREAM,0);/监听的套接字 SOCKADDR_IN socketadd; socketadd.sin_addr.S_un.S_addr = htonl(INADDR_ANY); /监听连接 socketadd.sin_family = AF_INET; socketadd.sin_port = htons(7001); /设置端口if( SOCKET_ERROR = bind(socksrv,(SOCKADDR*)&socketadd,sizeof(SOCKADDR) ) printf(绑定出错!n);WSACleanup();Sleep(SLEEPMS);

41、return; if( SOCKET_ERROR = listen(socksrv,5) ) printf(监听出错!);WSACleanup();Sleep(SLEEPMS); return; SOCKADDR_IN sockclient; int len = sizeof(SOCKADDR); SOCKET sockconn = accept(socksrv,(SOCKADDR*)&sockclient,&len);/建立连接的套节字 if(INVALID_SOCKET = sockconn ) printf(建立连接出错!n);WSACleanup( );Sleep(SLEEPMS); return; char sendDataSEND_

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 研究报告 > 设计方案

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁