一,实验流程
- 熟悉实验系统。熟悉实验系统的操作流程,帮助文档的debug功能等等
- 设计算法,实验分为三个函数,依次为等停式传输,回退N帧传输和选择性重传三种方式的实现
函数,其中,第一种等停式传输是第二种回退N传输的特例,第三种选择性传输和第二种传输方式的区别是在重传方面需要传送指定的帧,因此整个逻辑基本以第二个方法为框架进行修改。
对于第二个函数:做如下设计,
- 保存一个链表
waiting
作为输入缓冲区,当数据无法发送时,存入输入缓冲区。 - 保存一个窗口数组
window
,窗口内保存看现在等待确认的已经发送的数据包。 - 保存一个窗口上下界的序号
upper,lower
使用模运算来确定当前的数据对应于window
中
的哪一个位置 - 对于发送命令,当前
upper,lower
之间的差已经达到最大的窗口,那么就存入waiting
链表中,否则就将其发送,并将其缓存至window
数组的upper
对应的位置,并且upper
增加 - 对于
receive
命令,判断到来的ack,找到对应的在window
数组中的数据包,将lower
到该位置的数据包丢弃,并且重新发送输入缓冲区waiting
的数据直到缓冲区为空或者窗口重新到达最大。 - 对于
timeout
命令,查看其返回ack
,如果在窗口内部,则重新发送没有收到确认的数据包
- 对于第一个函数,将上述算法窗口设置为1即可
对于第三个函数,取消timeout
的选项,当收到receive
命令时,判断其是确认收到命令还是重发命令,如果是确认命令,和第二个函数操作相同,对于重发命令,则遍历窗口找到对应的seq
的数据包并且重新发送即可
二,实验遇到的问题
- 不要将数据帧的seq序列号和上述设计算法过程中的upper混淆,
- 对于数据frame中的size变量和发送函数中的bufferSize变量意义不同
- 超时回退N重发操作(这里是实验说明略有歧义?)需要重发整个窗口内所有数据,和说明略有不符。
- 实验说明上还有一点可能有一些歧义,在受到ack确认后重发操作实验说明上说重发一个数据,但是滑动窗口理应最大化窗口以达到最高的数据线路利用率,因此有些奇怪。但是尝试之后就可以确定时将发送窗口最大化。
实验代码
#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 MSG_TYPE_TIMEOUT 1
#define MSG_TYPE_SEND 2
#define MSG_TYPE_RECEIVE 3
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;
};
typedef struct Buffer {
frame* data;
int dataSize;
Buffer* nextBuffer;
};
typedef struct Window {
frame data;
int size;
};
Buffer* addFrameWait(Buffer* waiting, frame* pBuffer, int bufferSize) {
Buffer* b = (Buffer*)malloc(sizeof(Buffer));
b->data = (frame*)malloc(bufferSize);
memcpy(b->data, pBuffer, bufferSize);
b->dataSize = bufferSize;
b->nextBuffer = NULL;
if (waiting == NULL) {
waiting = b;
}
else {
Buffer* buf = waiting;
while (buf->nextBuffer != NULL) {
buf = buf->nextBuffer;
}
buf->nextBuffer = b;
}
return waiting;
}
int stud_slide_window_stop_and_wait(char *pBuffer, int bufferSize, UINT8 messageType)
{
static Window window[WINDOW_SIZE_STOP_WAIT];
static int upper = 0, lower = 0;
static Buffer* waiting = NULL;
switch (messageType) {
case MSG_TYPE_SEND: {
if (upper - lower < WINDOW_SIZE_STOP_WAIT) {
printf("-----send a message,seq is %d\n", ntohl((((frame*)pBuffer)->head).seq));
SendFRAMEPacket((unsigned char*)pBuffer, bufferSize);
window[upper%WINDOW_SIZE_STOP_WAIT].data = *(frame*)pBuffer;
window[upper%WINDOW_SIZE_STOP_WAIT].size = bufferSize;
upper++;
}
else {
printf("-----buffer a message.seq is %d\n", ntohl(((frame*)pBuffer)->head.seq));
waiting = addFrameWait(waiting, (frame*)pBuffer, bufferSize);
}
return 0;
}
case MSG_TYPE_RECEIVE: {
int ackBack = ntohl(((frame*)pBuffer)->head.ack);
printf("-----receive a message,ack is %d\n", ackBack);
int seqLoacl = ntohl(window[lower%WINDOW_SIZE_STOP_WAIT].data.head.seq);
if (ackBack == seqLoacl) {
if (waiting != NULL) {
SendFRAMEPacket((unsigned char*)waiting->data, waiting->dataSize);
window[lower%WINDOW_SIZE_STOP_WAIT].data = *(waiting->data);
window[lower%WINDOW_SIZE_STOP_WAIT].size = waiting->dataSize;
waiting = waiting->nextBuffer;
upper++;
}
lower++;
}
break;
}
case MSG_TYPE_TIMEOUT: {
int timeoutNum = *(unsigned*)pBuffer;
printf("-----timeout a message,seq is %d\n", timeoutNum);
SendFRAMEPacket((unsigned char*)&(window[0].data), window[0].size);
break;
}
}
return 0;
}
int stud_slide_window_back_n_frame(char *pBuffer, int bufferSize, UINT8 messageType)
{
static Window window[WINDOW_SIZE_BACK_N_FRAME];
static int upper = 0, lower = 0;
static Buffer* waiting = NULL;
switch (messageType) {
case MSG_TYPE_SEND: {
if (upper - lower < WINDOW_SIZE_BACK_N_FRAME) {
printf("-----send a message,seq is %d\n", ntohl((((frame*)pBuffer)->head).seq));
SendFRAMEPacket((unsigned char*)pBuffer, bufferSize);
window[upper%WINDOW_SIZE_BACK_N_FRAME].data = *(frame*)pBuffer;
window[upper%WINDOW_SIZE_BACK_N_FRAME].size = bufferSize;
upper++;
}
else {
printf("-----buffer a message.seq is %d\n", ntohl(((frame*)pBuffer)->head.seq));
waiting = addFrameWait(waiting, (frame*)pBuffer, bufferSize);
}
return 0;
}
case MSG_TYPE_RECEIVE: {
int ackBack = ntohl(((frame*)pBuffer)->head.ack);
printf("-----receive a message,ack is %d\n", ackBack);
for (int i = lower; i < upper; i++) {
int seqLocal = ntohl(window[i%WINDOW_SIZE_BACK_N_FRAME].data.head.seq);
if (ackBack == seqLocal) {
lower = i + 1;
while (upper - lower < WINDOW_SIZE_BACK_N_FRAME && waiting != NULL) {
SendFRAMEPacket((unsigned char*)waiting->data, waiting->dataSize);
window[upper%WINDOW_SIZE_BACK_N_FRAME].data = *(waiting->data);
window[upper%WINDOW_SIZE_BACK_N_FRAME].size = waiting->dataSize;
upper++;
waiting = waiting->nextBuffer;
}
break;
}
}
break;
}
case MSG_TYPE_TIMEOUT: {
unsigned timeOutSeq = *(unsigned*)pBuffer;
printf("-----timeout a frame seq is %d\n", timeOutSeq);
for (int i = lower; i < upper; i++) {
unsigned seqLocal = ntohl(window[i%WINDOW_SIZE_BACK_N_FRAME].data.head.seq);
if (seqLocal == timeOutSeq) {
printf("-----resend seq from %d to %d\n", lower, upper);
for (int j = lower; j < upper; j++) {
frame* fra = &(window[j%WINDOW_SIZE_BACK_N_FRAME].data);
int size = window[j%WINDOW_SIZE_BACK_N_FRAME].size;
SendFRAMEPacket((unsigned char*)fra, size);
}
break;
}
}
break;
}
}
return 0;
}
int stud_slide_window_choice_frame_resend(char *pBuffer, int bufferSize, UINT8 messageType)
{
static Window window[WINDOW_SIZE_BACK_N_FRAME];
static int upper = 0, lower = 0;
static Buffer* waiting = NULL;
switch (messageType) {
case MSG_TYPE_SEND: {
if (upper - lower < WINDOW_SIZE_BACK_N_FRAME) {
printf("-----send a message,seq is %d\n", ntohl((((frame*)pBuffer)->head).seq));
SendFRAMEPacket((unsigned char*)pBuffer, bufferSize);
window[upper%WINDOW_SIZE_BACK_N_FRAME].data = *(frame*)pBuffer;
window[upper%WINDOW_SIZE_BACK_N_FRAME].size = bufferSize;
upper++;
}
else {
printf("-----buffer a message.seq is %d\n", ntohl(((frame*)pBuffer)->head.seq));
waiting = addFrameWait(waiting, (frame*)pBuffer, bufferSize);
}
return 0;
}
case MSG_TYPE_RECEIVE: {
int ackKind = ntohl(((frame*)pBuffer)->head.kind);
if (ackKind == ack) {
int ackBack = ntohl(((frame*)pBuffer)->head.ack);
printf("-----receive a message,ack is %d\n", ackBack);
for (int i = lower; i < upper; i++) {
int seqLocal = ntohl(window[i%WINDOW_SIZE_BACK_N_FRAME].data.head.seq);
if (ackBack == seqLocal) {
lower = i + 1;
while (upper - lower < WINDOW_SIZE_BACK_N_FRAME && waiting != NULL) {
SendFRAMEPacket((unsigned char*)waiting->data, waiting->dataSize);
window[upper%WINDOW_SIZE_BACK_N_FRAME].data = *(waiting->data);
window[upper%WINDOW_SIZE_BACK_N_FRAME].size = waiting->dataSize;
upper++;
waiting = waiting->nextBuffer;
}
break;
}
}
}
else if (ackKind == nak) {
int nakBack = ntohl(((frame*)pBuffer)->head.ack);
printf("-----resend message .seq is %d\n", nakBack);
for (int i = lower; i < upper; i++) {
frame* fra = &(window[i%WINDOW_SIZE_BACK_N_FRAME].data);
int size = window[i%WINDOW_SIZE_BACK_N_FRAME].size;
int seqLocal = ntohl(fra->head.seq);
if (seqLocal == nakBack) {
SendFRAMEPacket((unsigned char*)fra, size);
break;
}
}
}
break;
}
}
return 0;
}