当前位置:文档之家› 滑动窗口实验

滑动窗口实验

计算机通信网络实验滑动窗口实验学院:班级:学号:姓名:2012年11月14日一、实验目的实现一个滑动窗口协议的数据传送部分,目的在于使学生更好地理解基本滑动窗口协议的基本工作原理,掌握计算机网络协议的基本实现技术。

二、原理简介(1)窗口机制滑动窗口协议的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口;同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口。

发送窗口和接收窗口的序号的上下界不一定要一样,甚至大小也可以不同。

不同的滑动窗口协议窗口大小一般不同。

发送方窗口内的序列号代表了那些已经被发送,但是还没有被确认的帧,或者是那些可以被发送的帧。

(2)1比特滑动窗口协议当发送窗口和接收窗口的大小固定为1时,滑动窗口协议退化为停等协议(stop-and-wait)。

该协议规定发送方每发送一帧后就要停下来,等待接收方已正确接收的确认(acknowledgement)返回后才能继续发送下一帧。

由于接收方需要判断接收到的帧是新发的帧还是重新发送的帧,因此发送方要为每一个帧加一个序号。

由于停等协议规定只有一帧完全发送成功后才能发送新的帧,因而只用一比特来编号就够了。

(3)后退n协议由于停等协议要为每一个帧进行确认后才继续发送下一帧,大大降低了信道利用率,因此又提出了后退n协议。

后退n协议中,发送方在发完一个数据帧后,不停下来等待应答帧,而是连续发送若干个数据帧,即使在连续发送过程中收到了接收方发来的应答帧,也可以继续发送,且发送方在每发送完一个数据帧时都要设置超时定时器,只要在所设置的超时时间内仍收到确认帧,就要重发相应的数据帧。

如:当发送方发送了N个帧后,若发现该N帧的前一个帧在计时器超时后仍未返回其确认信息,则该帧被判为出错或丢失,此时发送方就不得不重新发送出错帧及其后的N帧。

三、实验步骤1.编写滑动窗口协议的实现程序;2.在模拟实现,调试并运行自己编写的协议实现程序;3.了解协议的工作轨迹,如出现异常情况,在实验报告中写出原因分析。

四、实验过程1、程序功能及设计思路功能概述:用客户端/服务器模式代表A站、B站。

先由客户端输入服务器IP地址,然后客户端和服务器之间建立连接。

在服务器中可以自行设置发送窗口的大小(如果需要实现的是停等式协议,那么就将发送窗口设为1),设置完后,服务器开始向客户端根据滑动窗口(停等式)的协议规定发送数据帧,同时启动计时器,客户端收到数据帧后马上向服务器发送确认帧,服务器如果没有及时收到客户端的确认帧,就要返回到出错的地方进行重发。

实现滑动窗口协议的算法:发送端:1、socket初始化,绑定端口,监听,接受连接;2、设置发送窗口大小winsize;3、启动定时器,设置时间为0.2s*winsize;4、组帧并发送数据,即设置序号SN、数据data、长度msglen,之后发送一个窗口中的帧,每发送一个数据SN++;若发送完毕,则执行第6步;5、接收确认帧,每收到一个正确的确认帧,则改变滑动窗口上下限,若正确接收所有确认帧,则关闭定时器,返回第3步;若接收超时或有确认帧丢失,则SN=right_number,返回第3步;6、关闭socket,重新建立新的进程,等待下一个连接,返回第2步。

接收端:1、socket初始化,连接服务器;2、接收数据帧,将data存入缓存recvBuf,RN=SN+1;3、发送确认帧,若接收完毕,则关闭socket,否则返回第二步。

实现停等式协议的算法:和上述滑动窗口协议的算法类似,只需在发送端的第二步中将发送窗口大小winsize设置为1即可。

2、C语言程序代码:客户端Client://*********************** receiver.c ***************************** #pragma comment(lib, "ws2_32.lib") //WINSOCK API连接库文件#include <winsock.h> //WINSOCK API的头文件,需要包含在项目中#include <stdio.h>#include<string.h>int err;SOCKET sockClient; //用于客户端的SocketSOCKADDR_IN addrSrv; //服务端地址SOCKADDR_IN addrClient; //客户端地址char serverip[20]; //服务端IP// int i=0; //testint length = sizeof(struct sockaddr);int RN=0; //接收序号char recvBuf[10][100]; //发送帧测试内容,10条//---------------------------------------------------------------struct dataFrame //数据帧{int SN; //发送序号char data[100];int msglen; //字符长度,采用长度计数的组帧技术};struct dataFrame dframe;//************************ 初始化****************************** void initialization(){WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested = MAKEWORD( 1, 1 ); //WinSocket1.1版本err = WSAStartup( wVersionRequested, &wsaData );//wsaData用来存储系统传回的关于WinSocket的资料if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ){WSACleanup( );}return;}//***************** 连接服务器***********************void connecting(){printf("input server IP:");scanf("%s",serverip); //输入服务器ipaddrSrv.sin_addr.S_un.S_addr=inet_addr(serverip); //设置服务器地址addrSrv.sin_family=AF_INET;addrSrv.sin_port=htons(6000); // 设置端口号err=connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//连接服务器}//************************ 接收数据帧******************************void receiveFrame(){recv(sockClient,(char*)&dframe,sizeof(dframe),0); //接受数据strcpy(recvBuf[dframe.SN],dframe.data);printf("----------接收第%d号帧-------------\n",dframe.SN);RN=dframe.SN+1;//if(RN==2)Sleep(600); //用于测试//if(RN==2 && i==0){i++;return;} //用于测试send(sockClient,(char*)&RN,sizeof(RN),0); //发送希望接收到的数据编号}//************************main函数******************************** void main(){int i;initialization(); //初始化阶段,若返回值err=0,则表示初始化成功if(err!=0){printf("Intialization failed.\n");return;}sockClient=socket(AF_INET,SOCK_STREAM,0); //建立socket,SOCK_STREAM为遵从TCP/IP协议的socketif(sockClient==-1){printf("Building a socket failed.\n");return;}connecting(); //和发送端建立连接if(err!=0) //若返回值err=0,则表示建立连接成功{printf("connecting failed.\n");return;}else{printf("-------got connection from server.-------\n");}while (1) //循环接受数据{receiveFrame();//接收数据if(RN==10) //判断是否已接收完,本次测试一共为10帧数据帧{closesocket(sockClient); //关闭连接printf("-------close the socket.-------\n");break;}}printf("\n接收到的数据如下:\n");for(i=0;i<10;i++) //将接收的数据打印出来{printf("%s\n",recvBuf[i]);}while(1);WSACleanup();}//********************** end of program ************************服务器Server://*********************** server.c ***************************** #pragma comment(lib, "ws2_32.lib") //WINSOCK API连接库文件#include <winsock.h> //WINSOCK API的头文件,需要包含在项目中#include <stdio.h>#include<string.h>#include <stdlib.h>#include <windows.h>#pragma comment(lib,"Winmm.lib")int err;SOCKET sock; //用于服务器监听的SocketSOCKADDR_IN addrSrv; //服务端地址SOCKADDR_IN addrClient; //客户端地址int winsize; //滑动窗口大小int min,max;int length = sizeof(struct sockaddr);int RN; //接收序号int right_number=0; //已正确发送数据帧的计数器char sendBuf[10][100]={"Whether 60 or 16,","there is in every human being’s heart the lure of wonder,","the unfailing childlike appetite of what’s next and the joy of the game of living.", "so long as it receives messages of beauty, hope, cheer, courage","and power from men and from the Infinite, so long are you young.","When the aerials are down,","and your spirit is covered with snows of cynicism","and the ice of pessimism, then you are grown old, even at 20,","but as long as your aerials are up, to catch waves of optimism,","there is hope you may die young at 80."}; //发送帧测试内容,10条//---------------------------------------------------------------struct dataFrame //数据帧{int SN; //发送序号char data[100];int msglen; //字符长度,采用长度计数的组帧技术};struct dataFrame dframe;//************************ 初始化****************************** void initialization(){WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested = MAKEWORD( 1, 1 ); //WinSocket1.1版本err = WSAStartup( wVersionRequested, &wsaData );//wsaData用来存储系统传回的关于WinSocket的资料if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ){ WSACleanup( );}return;}//************************ 绑定端口****************************** void bindport(){addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//设置服务器地址,INADDR_ANY表示使用自己的IP地址addrSrv.sin_family=AF_INET;addrSrv.sin_port=htons(6000); //设定端口为6000err=bind(sock,(LPSOCKADDR)&addrSrv,sizeof(SOCKADDR));return;}//************************ 重发数据帧***************************** int resend(){err=10;dframe.SN=right_number;printf("超时,未收到第%d的确认帧,现重新发送...\n",right_number); return 0;}//************************ 发送数据帧***************************** int SendFrame(SOCKET*socketConn){UINT wTimerRes=200*winsize; //定义时间间隔为0.5sUINT wAccuracy=0; //定义分辨率UINT TimerID;dframe.SN=0;while(1){TimerID=timeSetEvent(wTimerRes,wAccuracy,(LPTIMECALLBACK)resend,(DWORD)(1), TIME_ONESHOT);while(dframe.SN>=min && dframe.SN<=max && dframe.SN<10){strcpy(dframe.data,sendBuf[dframe.SN]);dframe.msglen=strlen(sendBuf[dframe.SN]);send(*socketConn,(char*)&dframe,sizeof(struct dataFrame),0);//发送消息到客户端dframe.SN++;}while(1) //接受收端的确认帧{recv(*socketConn,(char*)&RN,sizeof(RN),0);if(err==10){timeKillEvent(TimerID);err=0;break;}if(right_number==RN-1){printf("收到第%d帧的确认帧...\n",RN-1);min=RN; //改变滑动窗口上下限max=min+winsize-1;right_number++;}else if(right_number<RN-1){printf("第%d帧丢失,现重发...\n",right_number);timeKillEvent(TimerID);dframe.SN=right_number;break;}if(right_number==dframe.SN){timeKillEvent(TimerID);break;}}if(RN==10) return 0;}}//线程函数用于处理一个客户端请求DWORD WINAPI ConnectClient(LPVOID socketConn){printf("input the size of slide window:");scanf("%d",&winsize);min=0;max=winsize-1;SendFrame(socketConn);printf("--------all message is delivered successful.---------\n\n");closesocket(*((SOCKET*)socketConn)); //关闭Socketprintf("--------disconnect with %s.---------\n\n",inet_ntoa(addrClient.sin_addr)); return 0;}void main(){HANDLE hThread;//线程句柄DWORD threadId;initialization(); //初始化阶段,若返回值err=0,则表示初始化成功if(err!=0){printf("Intialization failed.\n");return;}sock=socket(AF_INET,SOCK_STREAM,0);//建立socket,SOCK_STREAM为遵从TCP/IP协议的socketif(sock==-1){printf("Building a socket failed.\n");return;}bindport(); //绑定端口if(err!=0){printf("Binding a socket failed.\n");return;}if(listen(sock,5)==-1)//使服务器端的Socket进入监听状态,并设定可以建立的最大连接数为5 {printf("listening failed.\n");return;}printf("--------------------server waitting.--------------------\n");while (1) //循环等待请求{ SOCKET *socketConn =(SOCKET *)malloc(sizeof(SOCKET));//用于与客户端连接的socket*socketConn = accept(sock,(struct sockaddr*)&addrClient,&length);printf("connectingwith %s\n-------------------------------\n",inet_ntoa(addrClient.sin_addr));//开辟线程处理一个客户端请求hThread =CreateThread(NULL,0,ConnectClient,(LPVOID)socketConn,0,&threadId);}closesocket(sock);WSACleanup();system("pause");}3、实验结果1)停等式协议的测试在没有传输错误情况下,设置发送窗口为1,接收窗口也为1,在dos界面显示传递的整个过程,其中Server的IP为: 222.25.162.196 ,Client的IP为:222.25.162.5。

相关主题