NetRiver - 滑动窗口协议实验
来源:互联网 发布:简述算法的复杂度分析 编辑:程序博客网 时间:2024/05/01 02:15
本文的滑动窗口协议实验是NetRiver实验系统下的一个子实验,由清华大学开发,目前很多大学都在采用该系统作为计算机网络课程的Lab教学系统。(虽然bug很多而且说明指导书没什么用)
滑动窗口实验的三个函数代码实际上异曲同工,区别只在于窗口大小以及对TIMEOUT和NAK的处理上。
思路是利用数组把等待缓冲区和窗口都做成循环队列。当然链表也No problem。我也看过用C++的deque库实现的版本,优点是代码简洁,同样很有参考价值。然而个人测试发现网上流传的版本基本都无法通过NetRiver第二个子实验,经过个人调试发现是系统本身的bug。如果有兴趣读者可以自己尝试一下,找到第二个实验的问题所在。
话不多说,具体代码见下,附详细注释,以飨后人。
/** MIT license* Copyright © 2016 Maristie* * Permission is hereby granted, free of charge, to any person obtaining a copy of this software* and associated documentation files (the "Software"), to deal in the Software without restriction,* including without limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions:* The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software.* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/#include "sysinclude.h" extern void SendFRAMEPacket(unsigned char* pdata, unsigned int len);#define WINDOW_SIZE_STOP_WAIT 1 #define WINDOW_SIZE_BACK_N_FRAME 4#define max_wait_num 1000/** The following definitions are just as NetRiver instructions.*/typedef enum { data, ack, nak } frame_kind;typedef struct frame_head{ frame_kind kind; unsigned int seq; unsigned int ack; unsigned char data[100];};typedef struct frame{ frame_head head; unsigned int size;};/** stop and wait*/int stud_slide_window_stop_and_wait(char *pBuffer, int bufferSize, UINT8 messageType){ // two queues for window and waiting static frame *window[WINDOW_SIZE_STOP_WAIT] = { 0 }; static frame *waiting[max_wait_num] = { 0 }; static int win_begin = 0, win_end = 0, wait_begin = 0, wait_end = 0; static int win_num = 0, wait_num = 0; // when send if (messageType == MSG_TYPE_SEND) { // push pBuffer into waiting queue // allocate space for frame waiting[wait_end] = (frame*)malloc(sizeof(frame)); // copy pBuffer to waiting queue memcpy(waiting[wait_end], (frame*)pBuffer, sizeof(frame)); waiting[wait_end]->size = (unsigned int)bufferSize; wait_end = (wait_end + 1) % max_wait_num; wait_num++; // when window is not full if (win_num < WINDOW_SIZE_STOP_WAIT) { // pop one frame from waiting queue frame *temp = waiting[wait_begin]; wait_begin = (wait_begin + 1) % max_wait_num; wait_num--; // push the frame into window window[win_end] = temp; win_end = (win_end + 1) % WINDOW_SIZE_STOP_WAIT; win_num++; // try to send SendFRAMEPacket((unsigned char*)temp, temp->size); } // when window is full, no more needs to be done } // when receive else if (messageType == MSG_TYPE_RECEIVE) { frame *temp = (frame*)pBuffer; frame_kind kind = (frame_kind)ntohl((unsigned long)temp->head.kind); // check kind if (kind == nak) { // when nak, first find which frame needs to be resent int cursor = win_begin; unsigned int seq = ntohl(temp->head.ack); while (seq != ntohl(window[cursor]->head.seq)) cursor = (cursor + 1) % WINDOW_SIZE_STOP_WAIT; // then resend it SendFRAMEPacket((unsigned char*)window[cursor], window[cursor]->size); } else if (kind == ack) { // when ack, close windows before or equal it unsigned int ack = ntohl(temp->head.ack); while (ntohl(window[win_begin]->head.seq) <= ack) { // close a window free(window[win_begin]); win_begin = (win_begin + 1) % WINDOW_SIZE_STOP_WAIT; win_num--; // when waiting queue is not empty, then pop one and push into window if (wait_num > 0) { window[win_end] = waiting[wait_begin]; // try to send it SendFRAMEPacket((unsigned char*)window[win_end], window[win_end]->size); wait_begin = (wait_begin + 1) % max_wait_num; wait_num--; win_end = (win_end + 1) % WINDOW_SIZE_STOP_WAIT; win_num++; } } } } // when time out else if (messageType == MSG_TYPE_TIMEOUT) { UINT32 temp = ntohl(*((UINT32*)pBuffer)); int cursor = win_begin; // resend all frames after MSG_TYPE_TIMEOUT if (temp <= window[cursor]->head.seq) SendFRAMEPacket((unsigned char*)window[cursor], window[cursor]->size); cursor = (cursor + 1) % WINDOW_SIZE_STOP_WAIT; while (cursor != win_end) { if (temp <= window[cursor]->head.seq) SendFRAMEPacket((unsigned char*)window[cursor], window[cursor]->size); cursor = (cursor + 1) % WINDOW_SIZE_STOP_WAIT; } } return 0;}/** Almost same as stop-wait except WINDOW_SIZE_BACK_N_FRAME.*//** back n frame*/int stud_slide_window_back_n_frame(char *pBuffer, int bufferSize, UINT8 messageType){ // two queues for window and waiting static frame *window[WINDOW_SIZE_BACK_N_FRAME] = { 0 }; static frame *waiting[max_wait_num] = { 0 }; static int win_begin = 0, win_end = 0, wait_begin = 0, wait_end = 0; static int win_num = 0, wait_num = 0; // when send if (messageType == MSG_TYPE_SEND) { // push pBuffer into waiting queue // allocate space for frame waiting[wait_end] = (frame*)malloc(sizeof(frame)); // copy pBuffer to waiting queue memcpy(waiting[wait_end], (frame*)pBuffer, sizeof(frame)); waiting[wait_end]->size = (unsigned int)bufferSize; wait_end = (wait_end + 1) % max_wait_num; wait_num++; // when window is not full if (win_num < WINDOW_SIZE_BACK_N_FRAME) { // pop one frame from waiting queue frame *temp = waiting[wait_begin]; wait_begin = (wait_begin + 1) % max_wait_num; wait_num--; // push the frame into window window[win_end] = temp; win_end = (win_end + 1) % WINDOW_SIZE_BACK_N_FRAME; win_num++; // try to send SendFRAMEPacket((unsigned char*)temp, temp->size); } // when window is full, no more needs to be done } // when receive else if (messageType == MSG_TYPE_RECEIVE) { frame *temp = (frame*)pBuffer; frame_kind kind = (frame_kind)ntohl((unsigned long)temp->head.kind); // check kind if (kind == nak) { // when nak, first find which frame needs to be resent int cursor = win_begin; unsigned int seq = ntohl(temp->head.ack); while (seq != ntohl(window[cursor]->head.seq)) cursor = (cursor + 1) % WINDOW_SIZE_BACK_N_FRAME; // then resend it SendFRAMEPacket((unsigned char*)window[cursor], window[cursor]->size); } else if (kind == ack) { // when ack, close windows before or equal it unsigned int ack = ntohl(temp->head.ack); while (ntohl(window[win_begin]->head.seq) <= ack) { // close a window free(window[win_begin]); win_begin = (win_begin + 1) % WINDOW_SIZE_BACK_N_FRAME; win_num--; // when waiting queue is not empty, then pop one and push into window if (wait_num > 0) { window[win_end] = waiting[wait_begin]; // try to send it SendFRAMEPacket((unsigned char*)window[win_end], window[win_end]->size); wait_begin = (wait_begin + 1) % max_wait_num; wait_num--; win_end = (win_end + 1) % WINDOW_SIZE_BACK_N_FRAME; win_num++; } } } } // when time out else if (messageType == MSG_TYPE_TIMEOUT) { UINT32 temp = ntohl(*((UINT32*)pBuffer)); int cursor = win_begin; // resend all frames after MSG_TYPE_TIMEOUT // here is where I found the bug of lab system SendFRAMEPacket((unsigned char*)window[cursor], window[cursor]->size); cursor = (cursor + 1) % WINDOW_SIZE_BACK_N_FRAME; while (cursor != win_end) { SendFRAMEPacket((unsigned char*)window[cursor], window[cursor]->size); cursor = (cursor + 1) % WINDOW_SIZE_BACK_N_FRAME; } } return 0;}/** Almost same as back-n-frame.* The only difference is that back-n-frame has TIMEOUT, but choice-frame-resend has nak.*//** choice frame resend*/int stud_slide_window_choice_frame_resend(char *pBuffer, int bufferSize, UINT8 messageType){ // two queues for window and waiting static frame *window[WINDOW_SIZE_BACK_N_FRAME] = { 0 }; static frame *waiting[max_wait_num] = { 0 }; static int win_begin = 0, win_end = 0, wait_begin = 0, wait_end = 0; static int win_num = 0, wait_num = 0; // when send if (messageType == MSG_TYPE_SEND) { // push pBuffer into waiting queue // allocate space for frame waiting[wait_end] = (frame*)malloc(sizeof(frame)); // copy pBuffer to waiting queue memcpy(waiting[wait_end], (frame*)pBuffer, sizeof(frame)); waiting[wait_end]->size = (unsigned int)bufferSize; wait_end = (wait_end + 1) % max_wait_num; wait_num++; // when window is not full if (win_num < WINDOW_SIZE_BACK_N_FRAME) { // pop one frame from waiting queue frame *temp = waiting[wait_begin]; wait_begin = (wait_begin + 1) % max_wait_num; wait_num--; // push the frame into window window[win_end] = temp; win_end = (win_end + 1) % WINDOW_SIZE_BACK_N_FRAME; win_num++; // try to send SendFRAMEPacket((unsigned char*)temp, temp->size); } // when window is full, no more needs to be done } // when receive else if (messageType == MSG_TYPE_RECEIVE) { frame *temp = (frame*)pBuffer; frame_kind kind = (frame_kind)ntohl((unsigned long)temp->head.kind); // check kind if (kind == nak) { // when nak, first find which frame needs to be resent int cursor = win_begin; unsigned int seq = ntohl(temp->head.ack); while (seq != ntohl(window[cursor]->head.seq)) cursor = (cursor + 1) % WINDOW_SIZE_BACK_N_FRAME; // then resend it SendFRAMEPacket((unsigned char*)window[cursor], window[cursor]->size); } else if (kind == ack) { // when ack, close windows before or equal it unsigned int ack = ntohl(temp->head.ack); while (ntohl(window[win_begin]->head.seq) <= ack) { // close a window free(window[win_begin]); win_begin = (win_begin + 1) % WINDOW_SIZE_BACK_N_FRAME; win_num--; // when waiting queue is not empty, then pop one and push into window if (wait_num > 0) { window[win_end] = waiting[wait_begin]; // try to send it SendFRAMEPacket((unsigned char*)window[win_end], window[win_end]->size); wait_begin = (wait_begin + 1) % max_wait_num; wait_num--; win_end = (win_end + 1) % WINDOW_SIZE_BACK_N_FRAME; win_num++; } } } } // when time out else if (messageType == MSG_TYPE_TIMEOUT) { UINT32 temp = ntohl(*((UINT32*)pBuffer)); int cursor = win_begin; // resend all frames after MSG_TYPE_TIMEOUT SendFRAMEPacket((unsigned char*)window[cursor], window[cursor]->size); cursor = (cursor + 1) % WINDOW_SIZE_BACK_N_FRAME; while (cursor != win_end) { SendFRAMEPacket((unsigned char*)window[cursor], window[cursor]->size); cursor = (cursor + 1) % WINDOW_SIZE_BACK_N_FRAME; } } return 0;}
0 0
- NetRiver - 滑动窗口协议实验
- 解析NetRiver滑动窗口协议实验
- NetRiver - IPv6协议收发实验
- NetRiver - IPv6协议转发实验
- NetRiver - IPv4协议收发实验
- NetRiver - IPv4协议转发实验
- 滑动窗口协议实验
- 通信网络实验——滑动窗口协议模拟实现
- 滑动窗口协议
- 滑动窗口协议
- 滑动窗口协议
- 滑动窗口协议
- 滑动窗口协议
- 滑动窗口协议
- 滑动窗口协议
- 滑动窗口协议
- 滑动窗口协议
- TCP 滑动窗口协议
- 算法学习--4 设置一个有getMin功能的栈之栈的升级版(待修改)
- uva1347 Tour
- js的事件
- 【寒江雪】BMP位图文件格式分析
- Scala DataFrame生成技巧
- NetRiver - 滑动窗口协议实验
- CSDN-markdown编辑器
- JavaScript
- java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
- 3. 串的处理 在实际的开发工作中,对字符串的处理是最常见的编程任务。 本题目即是要求程序对用户输入的串进行处理。具体规则如下: 1. 把每个单词的首字母变为大写。 2. 把数字与
- HSSFWorkBooK用法 —Excel表的导出和设置
- 正则表达式---六(其他通用规则)
- iOS 开发 多线程详解之NSThread线程通信的操作与控制
- 表哥:我的大学生表弟工作4年赚了100万