搜档网
当前位置:搜档网 › 滑动窗口协议实验

滑动窗口协议实验

#include "sysinclude.h"
#include
#include
using namespace std;

extern void sendFRAMEPacket(unsigned char* pData, unsigned int len);

#define WINDOW_SIZE_STOP_WAIT 1
#define WINDOW_SIZE_BACK_N_FRAME 4
#define WINDOW_SIZE_CHOICE_FRAME_RESEND 4

//帧种类
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 *pframe; //帧指针
unsigned int size; //内容的长度
};

/*
* 停等协议
*/
//发送队列
queue my_queue_1;

/*
* 回退n帧
*/
//发送队列
deque my_queue_2;
//标记发送窗口是否已满,初始为未满
bool sendWindowFull = false;
//记录已发送但未收到正确接收确认的帧的数目,初始为0
int Count2 = 0;

/*
* 选择性重传
*/
//发送队列
deque my_queue_3;
//记录已发送但未收到正确接收确认的帧的数目,初始为0
int Count3 = 0;

/*
* 停等协议测试函数
*/
int stud_slide_window_stop_and_wait(char *pBuffer, int buffersize, UINT8 messageType)
{
unsigned int ack; //确认号
unsigned int num; //序列号
buffer my_buffer; //定义一帧的缓存

//根据messageType的不同,采取不同的处理方式
switch(messageType)
{
//发送帧的处理
case MSG_TYPE_SEND:
//准备一个新的帧
my_buffer.pframe = new frame;
//将待发送帧赋给缓存区帧指针指向的帧
*my_buffer.pframe = *(frame *)pBuffer;
//内容的长度
my_buffer.size = buffersize;
//将待发送帧压入发送队列
my_queue_1.push(my_buffer);
//如果发送窗口未满,那么发送一帧
if(!sendWindowFull)
{
//获得发送队列中最晚压入的帧
my_buffer = my_queue_1.back();
//调用发送帧函数
SendFRAMEPacket((unsigned char *)(my_buffer.pframe), my_buffer.size);
//发送窗口已满
sendWindowFull = true;
}
break;

//接收帧的处理
case MSG_TYPE_RECEIVE:
//将一个32位数由网络字节顺序转换为主机字节顺序
ack = ntohl(((frame *)pBuffer)->head.ack);
//获得发送队列中最早压入的帧
my_buffer = my_queue_1.front();
//如果发送队列中最早压入的帧得到确认,那么进行相应处理
if(ntohl(my_buffer.pframe->head.seq) == ack)
{
//从发送队列中弹出已经收到确认的帧
my_queue_1.pop();
//如果发送队列不为空,那么发送一帧
if(my_queue_1.size() != 0)
{
//获得发送队列中最早压入的帧
my_buffer = my_queue_1.front();
//调用发送函数
SendFRAMEPacket(((unsigned char *)my_buffer.pframe), my_buffer.size);
}
else
{
//设置发送窗口为未


sendWindowFull = false;
}
}
break;

//超时的处理
case MSG_TYPE_TIMEOUT:
//将一个32位数由网络字节顺序转换为主机字节顺序
num = ntohl(*(unsigned int *)pBuffer);
//获得发送队列中最早压入的帧
my_buffer = my_queue_1.front();
//如果是发送队列中最早压入的帧超时,那么重新发送该帧
if(num == ((* my_buffer.pframe).head.seq))
{
//调用发送帧函数
SendFRAMEPacket((unsigned char *)(my_buffer.pframe), my_buffer.size);
}
break;
}
return 0;
}

/*
* 回退n帧测试函数
*/
int stud_slide_window_back_n_frame(char *pBuffer, int buffersize, UINT8 messageType)
{
unsigned int ack; //确认号
unsigned int num; //序列号
int i, j; //临时变量
buffer my_buffer; //定义一帧的缓存

//根据messageType的不同,采取不同的处理方式
switch(messageType)
{
//发送帧的处理
case MSG_TYPE_SEND:
//准备一个新的帧
my_buffer.pframe = new frame;
//将待发送帧赋给缓存区帧指针指向的帧
(*my_buffer.pframe) = *(frame *)pBuffer;
//内容的长度
my_buffer.size = buffersize;
//将待发送帧压入发送队列
my_queue_2.push_back(my_buffer);
//如果发送窗口未满,那么发送一帧
if(Count2 < WINDOW_SIZE_BACK_N_FRAME)
{
//获得发送队列中最晚压入的帧
my_buffer = my_queue_2.back();
//调用发送函数
SendFRAMEPacket((unsigned char *)(my_buffer.pframe), my_buffer.size);
//计数器加1
Count2 ++;
}
break;

//接收帧的处理
case MSG_TYPE_RECEIVE:
//获取接收帧确认号
ack = ((frame *)pBuffer)->head.ack;
//通过循环找到确认帧对应的发送帧序列号
for (i = 0; i < WINDOW_SIZE_BACK_N_FRAME && i < my_queue_2.size(); i++)
{
my_buffer = my_queue_2[i];
if (ack == (*my_buffer.pframe).head.seq)
{
break;
}
}
//将该帧及之前的帧全部从发送队列中弹出
if (i < my_queue_2.size() && i < WINDOW_SIZE_BACK_N_FRAME)
{
for (j = 0; j <= i; j++)
{
my_queue_2.pop_front();
Count2--;
}
}
//获取当前计数器的值
j = Count2;
//将发送队列中可以发送的帧全部发送
for (; j < WINDOW_SIZE_BACK_N_FRAME && j < my_queue_2.size() && Count2 < WINDOW_SIZE_BACK_N_FRAME; j++)
{
my_buffer = my_queue_2[j];
//调用发送函数
SendFRAMEPacket((unsigned char *)(my_buffer.pframe), my_buffer.size);
Count2 ++;
}
break;

//超时的处理
case MSG_TYPE_TIMEOUT:
//将一个32位数由网络字节顺序转换为主机字节顺序
num = ntohl(*(unsigned int *)pBuffer);
//通过循环找到超时的帧的序列号
for (i = 0; i < my_queue_2.size() && i < WINDOW_SIZE_BACK_N_FRAME; i++)
{
my_buffer = my_queue_2[i];
if ((*my_buffer.pframe).head.seq == num)
break;
}
//根据帧序号将该帧以及后面发送过的帧重新发送
for (j

= i; j < WINDOW_SIZE_BACK_N_FRAME && j < my_queue_2.size(); j++)
{
my_buffer = my_queue_2[j];
//调用发送函数
SendFRAMEPacket((unsigned char *)(my_buffer.pframe), my_buffer.size);
}
break;
}
return 0;
}

/*
* 选择性重传测试函数
*/
int stud_slide_window_choice_frame_resend(char *pBuffer, int bufferSize, UINT8 messageType)
{
unsigned int Ack; //确认接收号
unsigned int Nak; //确认损坏号
int i, j; //临时变量
buffer my_buffer; //定义一帧的缓存

//根据messageType的不同,采取不同的处理方式
switch(messageType)
{
//发送帧的处理
case MSG_TYPE_SEND:
{
//准备一个新的帧
my_buffer.pframe = new frame;
//将待发送帧赋给缓存区帧指针指向的帧
*my_buffer.pframe = *(frame *)pBuffer;
//内容的长度
my_buffer.size = bufferSize;
//将待发送帧压入发送队列
my_queue_3.push_back(my_buffer);
//如果发送窗口未满,那么发送一帧
if(Count3 < WINDOW_SIZE_CHOICE_FRAME_RESEND)
{
//获得发送队列中最晚压入的帧
my_buffer = my_queue_3.back();
//调用发送函数
SendFRAMEPacket((unsigned char *)(my_buffer.pframe), my_buffer.size);
//计数器加1
Count3 ++;
}
break;
}

//接收帧的处理
case MSG_TYPE_RECEIVE:
{
//获取接收帧类型
int frame_kind = ntohl(((frame *)pBuffer)->head.kind);
//如果帧损坏,那么把出错的帧重新发送一次
if(frame_kind == nak)
{
Nak = ntohl(((frame *)pBuffer)->head.ack);
for(i = 0; i < i < WINDOW_SIZE_CHOICE_FRAME_RESEND && my_queue_3.size(); i ++)
{
//找到出错的帧,并重新发送
if(Nak == ntohl((*(my_queue_3[i].pframe)).head.seq))
{
SendFRAMEPacket((unsigned char *)(my_queue_3[i].pframe), my_queue_3[i].size);
break;
}
}
}
//如果帧正确接收,那么把之前的帧弹出,若窗口允许,则发送新帧
else
{
Ack = ntohl(((frame *)pBuffer)->head.ack);
//通过循环找到确认帧对应的发送帧序列号
for(i = 0; i < WINDOW_SIZE_CHOICE_FRAME_RESEND && i < my_queue_3.size(); i++)
{
my_buffer = my_queue_3[i];
if(Ack == ntohl((*my_buffer.pframe).head.seq))
{
break;
}
}
//将该帧及之前的帧全部从发送队列中弹出
if(i < my_queue_3.size() && i < WINDOW_SIZE_CHOICE_FRAME_RESEND)
{
for (j = 0; j <= i; j++)
{
my_queue_3.pop_front();
Count3 --;
}
}
//获取当前计数器的值
j = Count3;
//将发送队列中可以发送的帧全部发送
for (; j < WINDOW_SIZE_CHOICE_FRAME_RESEND && j < my_queue_3.size() && Count3 < WINDOW_SIZE_CHOICE_FRAME_RESEND; j ++)
{
my_buffer = my_queue_3[j];
//调用发送函数
SendFRAMEPacket((unsigned char *)(my_buffer.pframe), my_buffer.size);
//计数器加1
Count3 ++;
}

}
break;
}
}
return 0;
}

相关主题