问题描述
- 滑动窗口协议模拟代码求补全!!!!!
-
//发送方sender.cpp文件
#include
#include
#include"sender.h"
#include
#include
#include
#include
#define SLEEPMS 1000
#define MAXPOOL 8
#define RECEIVE_MAX_LENGTH 8
#define MAX_LENGTH 8
#define SEND_MAX_LENGTH 8
CRITICAL_SECTION gCS;void InitLine(LinkQueue *q) //初始化队列
{
q->front = q->rear = NULL;
}
int QueueEmpty(LinkQueue *q)//判断队列是否为空
{
return q->front == NULL && q->rear == NULL;
}
frame QueueFront(LinkQueue *q)
{
if (QueueEmpty(q))
{
printf("队列为空!n");
Sleep(SLEEPMS);
exit(0);
}
return q->front->head_data;
}
int QueueLen(LinkQueue *q)//计算队列长度
{
if (QueueEmpty(q))
{
return 0;
}
int num = 0;
Framenode *p = q->front;
while(p != NULL)
{
num++;
p = p->next;
}
return num;
}void GetFrameFromHost(LinkQueue *q) //数据帧发送完毕(收到确认帧)后,删除发送的数据帧(队头)
{
if(QueueLen(q) >= MAXPOOL)
{
printf("data %d 已准备好n", q->front->head_data.head.seq);
return;
}
Framenode *p=(Framenode *)malloc(sizeof(Framenode));
memset(p->head_data.head.data, 0, MAX_LENGTH);
srand((unsigned)time(NULL));
p->head_data.size = rand() % MAX_LENGTH; // 帧大小随机生成
memset(p->head_data.head.data, '1', p->head_data.size);
p->head_data.head.ack = -1;
p->head_data.head.kind = data;
p->head_data.head.seq = 0;
p->next =NULL;
if(QueueEmpty(q))
q->front = q->rear=p; // 首帧是待发送的帧
else
{
p->head_data.head.seq = (q->rear->head_data.head.seq + 1)%MAXPOOL;
q->rear->next =p;
q->rear =p;
}
printf("从主机得到:data %d,放入缓存n", p->head_data.head.seq);
GetFrameFromHost(q); // 由于实验需要,假设主机有足够多的数据帧要发送
}
void DeLine(LinkQueue *q) //将帧数据保存供提交主机,curw是打开的待接收数据的窗口
{
Framenode *p = NULL;
if(QueueEmpty(q))
{
printf("队列为空!n");
}
else
{
p = q->front;
q->front = p->next;
if (q->rear == p) q->rear = NULL;
printf("发送data %d, %d 成功!从缓存中删除n", p->head_data.head.seq, p->head_data.size);
free(p);
p = NULL;
}
}void main()//发送方主函数
{
printf("建立连接 ... n");
Begin:
WORD wVersionRequested;
WSADATA wsaData; //初始化socket库
wVersionRequested=MAKEWORD(1,1); //两个byte型合并成一个WORD型
int err=WSAStartup(wVersionRequested,&wsaData);
if(err!=0)
{
Sleep(SLEEPMS);
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
{
WSACleanup(); //中止Windows Sockets服务 WSAStartup()成对使用
Sleep(SLEEPMS);
return;
}
socketClient = socket(AF_INET,SOCK_STREAM,0);//监听的套接字
SOCKADDR_IN clientadd;
clientadd.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
clientadd.sin_family = AF_INET;
clientadd.sin_port = htons(7001);//设置连接端的IP、端口
if(SOCKET_ERROR==connect(socketClient,(SOCKADDR*)&clientadd,sizeof(SOCKADDR)) ) //连接
{
WSACleanup();
Sleep(SLEEPMS);
goto Begin;
}
char getData[RECEIVE_MAX_LENGTH];
memset(getData, 0, RECEIVE_MAX_LENGTH); //清零
if(recv(socketClient,getData,RECEIVE_MAX_LENGTH,0) == SOCKET_ERROR) //接受
{
printf("接受连接提示信息出错!n");
}
else
{
printf("%sn",getData);}
char sendData[SEND_MAX_LENGTH];
memset(sendData, 0, SEND_MAX_LENGTH);
strcpy(sendData, "你好接收方,我是发送方!");
if( SOCKET_ERROR == send(socketClient,sendData,strlen(sendData)+1,0) ) //发送
{
printf("发送连接提示信息出错!n");
WSACleanup();
closesocket(socketClient);
Sleep(SLEEPMS);
return;
}
printf("按任意键继续!n");
while (!kbhit()) {}; //等待开始
Sleep(SLEEPMS);
printf("1bit滑动窗口协议:发送方,发送窗口=1n");
LinkQueue QueueQ;
InitLine(&QueueQ);
frame packetsend; //data
frame packetreceive; // ack,nak
unsigned long tick = GetTickCount();
int ret = 0;
HANDLE hThread;
while(1)
{
GetFrameFromHost(&QueueQ); //从主机取数据帧
memset(&packetsend, 0, sizeof(packetsend));
Sleep(SLEEPMS);
printf("n");
packetsend = QueueFront(&QueueQ); //取数据帧
ret = send(socketClient, (char *)&packetsend, sizeof(packetsend), 0);//发送data
if(ret == SOCKET_ERROR)
{
printf("发送数据出错!n");
continue;
}
printf("发送数据帧:data %d, %dn", packetsend.head.seq, packetsend.size);
const unsigned long timeOut = 5 * 1000; //设置超时计时器 5秒超时
memset(&packetreceive, 0, sizeof(packetreceive));
Sleep(SLEEPMS);
printf("n");HANDLE hThrea;
InitializeCriticalSection(&gCS); // 初始化临界区hThread=CreateThread(NULL, 0, ReceiveFun, (LPVOID)&packetreceive, 0, NULL);
int r = WaitForMultipleObjects(1, &hThread, TRUE, timeOut);
DeleteCriticalSection(&gCS); //与InitializeCriticalSection(&gCS);成对使用
if(ret == SOCKET_ERROR || ret == SOCKET_DISCONN)
{
printf("接受出错!Press any key to continuen");
while (!kbhit()) {};
continue;
}
if(r == WSA_WAIT_TIMEOUT) //判断超时
{
TerminateThread(hThread, 0); //终止线程
printf("超时重传:data %d, %dn", packetsend.head.seq,packetsend.size);
}
else if(packetsend.head.seq == packetreceive.head.ack)
{
srand((unsigned)time(NULL));
switch(rand() % 5) //假定产生随机结果,20%的概率超时
{
case 0:
printf("接收方发送回复超时(ack丢失模拟):%dn", packetsend.head.seq);
printf("超时重传:data %d, %dn", packetsend.head.seq,packetsend.size);
break;
default:
if(packetreceive.head.kind == ack)
{
printf("接受ack帧:ack %dn", packetreceive.head.ack);
DeLine(&QueueQ);
}
else if(packetreceive.head.kind == nak)
{
printf("接受nak帧:nak %dn", packetsend.head.seq);
}
break;
}
}
else printf("帧序号出错: %dn", packetreceive.head.ack);
if(GetTickCount() - tick > 20 * TIMEOUT) //设置时间20秒
{
printf("持续时间20s. 按q退出,其他键继续n");
int kbc = getchar();
if(kbc == 'q' || kbc == 'Q')
break;
}
}
printf("按任意键退出!n");
while (!kbhit()) {};
Sleep(SLEEPMS);
printf("谢谢使用!n");
WSACleanup();
closesocket(socketClient);
Sleep(SLEEPMS);
}
DWORD WINAPI ReceiveFun(LPVOID pArg)
{
EnterCriticalSection(&gCS);//进入critical section
frame *packetreceive = (frame *)pArg;
ret = recv(socketClient, (char *)packetreceive, sizeof(*packetreceive), 0);
LeaveCriticalSection(&gCS); //线程用毕,离开critical section
return ret;
}
//头文件sender.h部分
#includetypedef enum {data = 1,ack,nak,tout} frame_kind; //帧类型
typedef struct frame_head
{
frame_kind kind; //帧类型
unsigned int seq; //序列号
unsigned int ack; //确认号
unsigned char data[MAX_LENGTH]; //数据
}Head;
typedef struct frame
{
frame_head head; //帧头
unsigned int size; //数据的大小
} Frame;
typedef struct framenode //队列节点类型
{
frame head_data;
struct framenode *next;
} Framenode;
typedef struct{
Framenode *front; //队头指针
Framenode *rear; //队尾指针
} LinkQueue;
解决方案
现在缺什么代码呢?