Exp1滑动窗口协议实验报告【实验目标】理解和掌握“滑动窗口”技术。基于计算机网络实验系统NetRiver进行。NetRiver系统提供了各实验的上下文和接口函数,利用C/C++编程语言实现典型协议的核心部分。使用NetRiver系统完成程序代码的编译、调试和测试,验证协议实现的正确性。【实验原理】1-bit滑动窗口协议1-bit滑动窗口协议中,需要保证发送窗口大小不超过1。我们用ack_expected表示发送窗口下界,即希望得到确认的帧号;用window_size表示当前发送窗口的大小。当有事件到达时,根据事件的类型进行相应处理:超时事件:此时pBuffer指向的UINT32类型存储的是主机序的序列号seq,将seq与当前窗口区间[ack_expected,ack_expected+windoe_size)进行比较,从seq开始连续进行发送。网络层发送事件:此时网络层想要发送一个新帧,pBuffer指向的是网络层准备好的帧,我们将该帧放入缓冲队列,并在发送窗口未满时进行1次发送。帧到达事件:此时我们收到了一个帧,通过ntohl将其确认号转化成主机序ack,然后对比ack是否等于ack_expected,若是则发送窗口下界加1,此时若还有帧在缓冲区则尝试进行1次发送,发送窗口上界加1。回退n帧滑动窗口协议回退n帧滑动窗口协议和1-bit滑动窗口协议相比,主要的区别在于窗口大小的不同,以及处理超时事件时,应从超时的帧开始进行连续发送。其他事件的处理则没有不同。【实验中遇到的问题】起始编号实验中帧号从1开始编号,而不是通常认为的0。静态变量由于两个函数将被分别连续调用,故不适合使用全局变量,否则将出现未初始化的现象。这里我使用了函数内的静态变量来保证合适的初始值。实验系统不稳定实验过程中挺经常遇到服务器超时的现象,而且有时同一个程序运行两次也会有不同的结果。一个经验性的做法是在程序中增加一些cout语句,实践上能够保证结果正确,但具体原因尚不清楚。【源代码】#includesysinclude.h#includedequeusingnamespacestd;externvoidSendFRAMEPacket(unsignedchar*pData,unsignedintlen);#defineWINDOW_SIZE_STOP_WAIT1#defineWINDOW_SIZE_BACK_N_FRAME4//帧类型typedefenum{data,ack,nak}frame_kind;//帧头typedefstructframe_head{frame_kindkind;//帧类型unsignedintseq;//序号unsignedintack;//确认号unsignedchardata[100];//数据};//完整帧typedefstructframe{frame_headhead;//帧头unsignedintsize;//数据的大小};//队列元素typedefstructstore_elm{frame*pframe;//帧头unsignedintlen;//数据长度};/**停等协议测试函数*/intstud_slide_window_stop_and_wait(char*pBuffer,intbufferSize,UINT8messageType){//发送缓冲区staticdequestore_elmbuffDeque;staticUINT32window_size=0;staticUINT32ack_expected=1;//起始编号为1UINT32seq,ack;store_elms;switch(messageType){caseMSG_TYPE_TIMEOUT:seq=*((UINT32*)pBuffer);//给出主机序if(ack_expected=seq&&seqack_expected+window_size){for(UINT32i=seq-ack_expected;iwindow_size;++i)SendFRAMEPacket((unsignedchar*)(buffDeque[i].pframe),buffDeque[i].len);}break;caseMSG_TYPE_SEND:s.pframe=newframe;//缓存新帧*s.pframe=*(frame*)pBuffer;s.len=bufferSize;buffDeque.push_back(s);if(window_sizeWINDOW_SIZE_STOP_WAIT){//尝试发送s=buffDeque[window_size++];SendFRAMEPacket((unsignedchar*)(s.pframe),s.len);}break;caseMSG_TYPE_RECEIVE:ack=ntohl(((frame*)pBuffer)-head.ack);ack_expected=ntohl(buffDeque[0].pframe-head.seq);if(ack==ack_expected){//如果是等待的帧buffDeque.pop_front();--window_size;++ack_expected;if(buffDeque.size()0&&window_sizeWINDOW_SIZE_STOP_WAIT){//尝试发送s=buffDeque[window_size++];SendFRAMEPacket((unsignedchar*)(s.pframe),s.len);}}break;default:break;}return0;}/**回退n帧测试函数*/intstud_slide_window_back_n_frame(char*pBuffer,intbufferSize,UINT8messageType){//发送缓冲区staticdequestore_elmbuffDeque;staticUINT32window_size=0;staticUINT32ack_expected=1;//起始编号为1UINT32seq,ack;store_elms;coutmessageType:(char)('0'+messageType)endl;switch(messageType){caseMSG_TYPE_TIMEOUT:seq=*((UINT32*)pBuffer);//给出主机序if(ack_expected=seq&&seqack_expected+window_size){for(UINT32i=seq-ack_expected;iwindow_size;++i)SendFRAMEPacket((unsignedchar*)(buffDeque[i].pframe),buffDeque[i].len);}break;caseMSG_TYPE_SEND:s.pframe=newframe;//缓存新帧*s.pframe=*(frame*)pBuffer;s.len=bufferSize;buffDeque.push_back(s);if(window_sizeWINDOW_SIZE_BACK_N_FRAME){//尝试发送s=buffDeque[window_size++];SendFRAMEPacket((unsignedchar*)(s.pframe),s.len);}break;caseMSG_TYPE_RECEIVE:ack=ntohl(((frame*)pBuffer)-head.ack);ack_expected=ntohl(buffDeque[0].pframe-head.seq);while(ack=ack_expected){//如果是等待的帧buffDeque.pop_front();--window_size;++ack_expected;if(buffDeque.size()0&&window_sizeWINDOW_SIZE_BACK_N_FRAME){//尝试发送s=buffDeque[window_size++];SendFRAMEPacket((unsignedchar*)(s.pframe),s.len);}}break;caseMSG_TYPE_RESEND:seq=*((UINT32*)pBuffer);//给出主机序default:break;}return0;}