基于滑动窗口协议写的程序(UDP实现) .
正好有一个大作业关于用socket实现滑动窗口协议,所以写了一个,模拟接收方与发送方窗口都是2,用两个线程实现。
下面是代码,注释的比较详细了。
socket_udp.h
- #include<stdio.h>
- #include<Windows.h>
- #include<stdlib.h>
- #include<time.h>
- #include<math.h>
- //#include "winsock2.h"
- #pragma comment(lib,"WS2_32.LIB")
- #define SWS 2//定义发送窗口
- #define RWS 2//定义接收窗口
- typedef u_char SwpSeqno;//定义序列号
- typedef HANDLE Semaphore;//定义信号量
- typedef HANDLE Event;//定义定时器事件
- typedef char Msg;//定义消息的类型
- typedef struct {
- SwpSeqno SeqNum;//帧序号
- SwpSeqno AckNum;//已收到确认帧序号
- char Flags;//8 bit 的标志
- }SwpHdr;
- struct sendQ_slot{
- Event timeout;//与发送方相关的超时事件
- Msg *msg;//发送的消息
- };
- struct recvQ_slot{
- int recevied; //msg是正确的吗?
- Msg *msg;
- };
- typedef struct {
- //发送方状态
- SwpSeqno LAR;//最近的收到的ACK序号
- SwpSeqno LFS;//最近的发送的帧序号
- Semaphore sendWindowNotFull;//信号量,控制滑动窗口的界
- SwpHdr hdr;
- struct sendQ_slot sendQ[SWS];//发送消息
- //接收方状态
- SwpSeqno NFE;//期待的下一帧的序号
- struct recvQ_slot recvQ[RWS];//接收消息
- }SwpState;
- //超时线程参数
- typedef struct{
- int time;
- Msg frame[11];
- }TimeOutType;
#include<stdio.h>
#include<Windows.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
//#include "winsock2.h"
#pragma comment(lib,"WS2_32.LIB") #define SWS 2//定义发送窗口
#define RWS 2//定义接收窗口 typedef u_char SwpSeqno;//定义序列号
typedef HANDLE Semaphore;//定义信号量
typedef HANDLE Event;//定义定时器事件
typedef char Msg;//定义消息的类型 typedef struct {
SwpSeqno SeqNum;//帧序号
SwpSeqno AckNum;//已收到确认帧序号
char Flags;//8 bit 的标志
}SwpHdr;
struct sendQ_slot{
Event timeout;//与发送方相关的超时事件
Msg *msg;//发送的消息
};
struct recvQ_slot{
int recevied; //msg是正确的吗?
Msg *msg;
};
typedef struct {
//发送方状态
SwpSeqno LAR;//最近的收到的ACK序号
SwpSeqno LFS;//最近的发送的帧序号
Semaphore sendWindowNotFull;//信号量,控制滑动窗口的界
SwpHdr hdr;
struct sendQ_slot sendQ[SWS];//发送消息 //接收方状态
SwpSeqno NFE;//期待的下一帧的序号
struct recvQ_slot recvQ[RWS];//接收消息
}SwpState; //超时线程参数
typedef struct{
int time;
Msg frame[11];
}TimeOutType;
socket_udp.cpp
- #include"socket_udp.h"
- #define HLEN 3//帧头部长度
- #define DLEN 8//帧数据长度
- #define ALEN 3//ACK帧长度
- #define SWP_SEND_TIMEOUT 500//定义超时长度为500ms
- #define LINK "127.0.0.1"//定义要发送的对象
- #define FLAG_ACK_VALID 'a'//定义ACK帧
- #define FLAG_DATA_VALID 'd'//定义数据帧
- #define SUCCESS 1;//定义已经成功收到的消息
- static void sendSWP(SwpState *state,Msg *frame);//发送函数
- static int deliverSWP(SwpState *state,Msg *frame);//接收并返回ACK函数
- //发送
- static void semWait(Semaphore *sendWindowNotFull);//信号量处理(-1)
- static void store_swp_hdr(SwpHdr hdr,char *hbuf);//存储发送的帧头部
- static void msgAddHdr(Msg *frame,char *hbuf);//将头部添加到帧上
- static void msgSaveCopy(char *msg,Msg *frame);//将消息添加到帧上
- static Event evSchedule(Msg *frame,int time);//调用定时器函数
- DWORD WINAPI swpTimeout(LPVOID threadtype);//创建定时器线程
- static void send_socket(char *addr,Msg *frame,int size);//UDP发送
- static void mlisten();//监听数据
- static void msend();//发送数据
- //接收
- static char *msgStripHdr(Msg *frame,int length);//获取帧的头部
- static void load_swp_hdr(SwpHdr *hdr,char *hbuf);//帧头部提取字符串
- static bool swpInWindow(SwpSeqno AckNum,SwpSeqno LAR,SwpSeqno LFS);//判断收到的帧是否在窗口内
- static void evCancel(Event *);//取消超时定时器
- static void msgDestroy(Msg *msg);//释放msg空间
- static void semSignal(Semaphore *sendWindowNotFull);//信号量处理(+1)
- static void prepare_ack(Msg *msg,SwpSeqno n);//组成ACK消息
- //全局变量
- HANDLE hlisten;
- HANDLE hsend;
- SwpState *send_state;
- Msg *frame;
- HANDLE Mutex = CreateMutex(NULL,FALSE,NULL);
- void main(){
- //模拟滑动窗口接收和发送过程
- //初始化SwpState,Msg,数据帧组帧
- //启动两个线程,模拟收发
- //监听终止
- frame=(Msg *)malloc(11*sizeof(Msg));
- //初始化消息
- //frame="message";//8个字节的数据
- //初始化状态
- send_state=(SwpState *)malloc(sizeof(SwpState));
- send_state->LAR='0';
- send_state->LFS='0';
- send_state->NFE='0';
- send_state->sendWindowNotFull=CreateSemaphore(NULL,SWS,SWS,NULL);
- if(send_state->sendWindowNotFull==NULL){
- printf("CreateSemaphore error\n",GetLastError());
- exit(0);
- }
- send_state->hdr.SeqNum='0';//3个字节头部
- send_state->hdr.AckNum='0';
- send_state->hdr.Flags='d';
- for(int i=0;i<SWS;i++){
- send_state->sendQ[i].msg=(Msg *)malloc(8*sizeof(Msg));
- send_state->sendQ[i].msg="message";
- send_state->sendQ[i].timeout=NULL;
- }
- for(int i=0;i<RWS;i++){
- send_state->recvQ[i].msg=(Msg *)malloc(8*sizeof(Msg));
- send_state->recvQ[i].msg="message";
- send_state->recvQ[i].recevied=NULL;
- }
- //初始化UDP函数
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2,1),&wsaData)){
- printf("Winsock initializing fail\n");
- WSACleanup();
- return;
- }
- //建立监听线程
- hlisten=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) mlisten,NULL,CREATE_SUSPENDED,NULL);
- ResumeThread(hlisten);
- if(hlisten==NULL){
- printf("thread_listen create fail\n");
- }
- hsend=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) msend,NULL,CREATE_SUSPENDED,NULL);
- ResumeThread(hsend);
- if(hsend==NULL){
- printf("thread_send create fail\n");
- }
- Sleep(10000);
- WSACleanup();
- }
- static void msend(){
- printf("thread_send started\n");
- while(1){
- sendSWP(send_state,frame);
- }
- printf("thread_send quit\n");
- }
- static void sendSWP(SwpState *state,Msg *frame){
- struct sendQ_slot *slot;//等待发送
- char hbuf[HLEN];//附加在帧头部的字符串
- //等待打开发送窗口
- semWait(&state->sendWindowNotFull);
- WaitForSingleObject(Mutex,INFINITE);
- state->hdr.SeqNum=state->LFS++;
- printf("send %d\n",state->hdr.SeqNum);
- slot=&(state->sendQ[state->hdr.SeqNum % SWS]);
- store_swp_hdr(state->hdr,hbuf);
- msgAddHdr(frame,hbuf);
- msgSaveCopy(slot->msg,frame);
- slot->timeout=evSchedule(frame,SWP_SEND_TIMEOUT);
- send_socket(LINK,frame,HLEN+DLEN);
- ReleaseMutex(Mutex);
- }
- static int deliverSWP(SwpState *state,Msg *frame){
- SwpHdr hdr;
- char *hbuf;
- hbuf = msgStripHdr(frame,HLEN);
- load_swp_hdr(&hdr,hbuf);
- if(hdr.Flags == FLAG_ACK_VALID){
- //发送方收到一个ACK,处理ACK帧
- if(swpInWindow(hdr.AckNum,state->LAR,state->LFS)){
- do{
- WaitForSingleObject(Mutex,INFINITE);
- printf("send get ack %d\n",hdr.AckNum);
- struct sendQ_slot *slot;
- slot=&state->sendQ[state->LAR++ % SWS];
- evCancel(&slot->timeout);
- //msgDestroy(slot->msg);
- semSignal(&state->sendWindowNotFull);
- ReleaseMutex(Mutex);
- }while(state->LAR==hdr.AckNum);
- }
- }
- if(hdr.Flags == FLAG_DATA_VALID){
- //接收到数据帧,处理数据帧
- WaitForSingleObject(Mutex,INFINITE);
- struct recvQ_slot *slot;
- slot=&state->recvQ[hdr.SeqNum % RWS];
- if(!swpInWindow(hdr.SeqNum,state->NFE,state->NFE+RWS-1)){
- ReleaseMutex(Mutex);
- return SUCCESS;
- }
- msgSaveCopy(slot->msg,frame);
- slot->recevied=TRUE;
- if(hdr.SeqNum==state->NFE){
- Msg *m=(Msg *)malloc(3*sizeof(Msg));
- while(slot->recevied){
- //deliver(HLP,&slot->msg)//传向上层
- printf("receive get data %d\n",hdr.SeqNum);
- printf("%s\n",slot->msg);
- //msgDestroy(slot->msg);
- slot->recevied=FALSE;
- slot=&state->recvQ[state->NFE++ % RWS];
- }
- prepare_ack(m,state->NFE-1);
- send_socket(LINK,m,ALEN);
- msgDestroy(m);
- }
- ReleaseMutex(Mutex);
- }
- return SUCCESS;
- }
- static void semWait(Semaphore *sendWindowNotFull){
- DWORD wait_for_semaphore;
- wait_for_semaphore = WaitForSingleObject(*sendWindowNotFull,-1);
- }
- static void store_swp_hdr(SwpHdr hdr,char *hbuf){
- hbuf[0]=hdr.SeqNum;
- hbuf[1]=hdr.AckNum;
- hbuf[2]=hdr.Flags;
- }
- static void msgAddHdr(Msg *frame,char *hbuf){
- frame[0]=hbuf[0];
- frame[1]=hbuf[1];
- frame[2]=hbuf[2];
- }
- static void msgSaveCopy(char *msg,Msg *frame){
- int j=0;
- for(int i=3;i<11;i++){
- frame[i]=msg[j];
- j++;
- }
- }
- static Event evSchedule(Msg *frame,int time){
- TimeOutType *timetype=(TimeOutType *)malloc(sizeof(TimeOutType));//超时线程参数
- timetype->time=time;
- for(int i=0;i<11;i++){
- timetype->frame[i]=frame[i];
- }
- //创建定时器线程
- DWORD targetThreadID;
- HANDLE Timer=CreateThread(NULL,0,swpTimeout,timetype,CREATE_SUSPENDED,NULL);
- ResumeThread(Timer);
- if(Timer==NULL){
- printf("thread_timeout create fail\n");
- }
- return Timer;
- }
- DWORD WINAPI swpTimeout(LPVOID threadtype){
- printf("thread_timeout started\n");
- TimeOutType *timetype=(TimeOutType *)threadtype;
- int time=timetype->time;
- Msg *frame;
- DWORD result=1;
- frame=timetype->frame;
- SetTimer(NULL,0,time,NULL);
- MSG msg;
- BOOL bRet;
- while (TRUE)
- //该循环捕捉定时器消息
- {
- bRet = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
- if (bRet == - 1){
- // handle the error and possibly exit
- }
- else if (bRet && msg.message == WM_TIMER){//定时器
- //处理超时事件
- printf("send重发%d\n",frame[0]);
- send_socket(LINK,frame,HLEN+DLEN);//超时重发
- }
- else{
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- printf("thread_timeout_quit");
- return result;
- }
- static void mlisten(){
- printf("thread_listen started\n");
- SOCKET socket1;
- struct sockaddr_in local;
- struct sockaddr_in from;
- int fromlen =sizeof(from);
- local.sin_family=AF_INET;
- local.sin_port=htons(8808); ///监听端口
- local.sin_addr.s_addr=INADDR_ANY; ///本机
- socket1=socket(AF_INET,SOCK_DGRAM,0);
- bind(socket1,(struct sockaddr*)&local,sizeof(local));
- while (1){
- char buffer[11]={0};
- if (recvfrom(socket1,buffer,sizeof(buffer),0,(struct sockaddr*)&from,&fromlen)!=SOCKET_ERROR){
- deliverSWP(send_state,buffer);
- }
- }
- closesocket(socket1);
- printf("listen thread quit\n");
- }
- static void send_socket(char *addr,Msg *frame,int size){
- //UDP发送函数
- SOCKET socket1;
- struct sockaddr_in server;
- int len =sizeof(server);
- server.sin_family=AF_INET;
- server.sin_port=htons(8808); ///server的监听端口
- server.sin_addr.s_addr=inet_addr(LINK); ///server的地址
- socket1=socket(AF_INET,SOCK_DGRAM,0);
- if (sendto(socket1,frame,sizeof(frame),0,(struct sockaddr*)&server,len)!=SOCKET_ERROR){
- }
- closesocket(socket1);
- }
- static char *msgStripHdr(Msg *frame,int length){
- char *result=(char *)malloc(sizeof(char));
- for(int i=0;i<length;i++){
- result[i]=frame[i];
- }
- return result;
- }
- static void load_swp_hdr(SwpHdr *hdr,char *hbuf){
- hdr->SeqNum=hbuf[0];
- hdr->AckNum=hbuf[1];
- hdr->Flags=hbuf[2];
- }
- static bool swpInWindow(SwpSeqno seqno,SwpSeqno min,SwpSeqno max){
- SwpSeqno pos,maxpos;
- pos=seqno-min;
- maxpos=max-min+1;
- return pos<maxpos;
- }
- static void evCancel(Event *thread){
- TerminateThread(*thread,0);
- printf("thread_timeout quit\n");
- }
- static void msgDestroy(Msg *msg){
- free(msg);
- }
- static void semSignal(Semaphore *sendWindowNotFull){
- if(!ReleaseSemaphore(*sendWindowNotFull,1,NULL)){
- printf("ReleseSemphore error\n");
- exit(0);
- }
- }
- static void prepare_ack(Msg *m,SwpSeqno n){
- //ack组帧
- m[0]=NULL;
- m[1]=n;
- m[2]='a';
- }
基于滑动窗口协议写的程序(UDP实现) .的更多相关文章
- TCP协议的滑动窗口协议以及流量控制
参考资料 http://blog.chinaunix.net/uid-26275986-id-4109679.html http://network.51cto.com/art/201501/4640 ...
- 面试之路(29)-TCP流量控制和拥塞控制-滑动窗口协议详解
拥塞: 拥塞发生的主要原因在于网络能够提供的资源不足以满足用户的需求,这些资源包括缓存空间.链路带宽容量和中间节点的处理能力.由于互联网的设计机制导致其缺乏"接纳控制"能力,因此在 ...
- 面试连环炮系列(二十):TCP的滑动窗口协议是什么
TCP的滑动窗口协议是什么 滑动窗口协议,用于网络数据传输时的流量控制,以避免拥塞的发生.该协议允许发送方在停止并等待确认前发送多个数据分组.由于发送方不必每发一个分组就停下来等待确认,因此该协议可以 ...
- TCP协议总结--停止等待协议,连续ARQ协议,滑动窗口协议
前言:在学习tcp三次握手的过程之中,由于一直无法解释tcpdump命令抓的包中seq和ack的含义,就将tcp协议往深入的了解了一下,了解到了几个协议,做一个小结. 先来看看我的问题: 这是用tcp ...
- UNIX网络编程——TCP 滑动窗口协议
什么是滑动窗口协议? 一图胜千言,看下面的图.简单解释下,发送和接受方都会维护一个数据帧的序列,这个序列被称作窗口.发送方的窗口大小由接受方确定,目的在于控制发送速度,以免接受方的缓存不够大, ...
- 一篇带你读懂TCP之“滑动窗口”协议
前言 你现在的努力,是为了以后有更多的选择. 在上一篇文章通过"表白"方式,让我们快速了解网络七层协议了解了网络七层协议. 接下来我们要把重心放在网络传输的可靠性上面.一起来看TC ...
- TCP滑动窗口协议
TCP的首部中有一个很重要的字段就是16位长的窗口大小,它出现在每一个TCP数据报中,配合32位的确认序号,用于向对端通告本地socket的接收窗口大小.也就是说,如果本地socket发送一个TCP ...
- TCP之四:TCP 滑动窗口协议 详解
滑动窗口机制 滑动窗口协议的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口:同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口.发送窗口和接收窗口的序号的 ...
- 流水线机制、滑动窗口协议、GBN、SR
一.滑动窗口协议 为了解决停等操作的性能问题(发了一个分组之后一直等到确认了这个分组才发下一个),推出了流水线机制,提供资源利用率.就是允许发送方在收到对方的ACK前,发送多个分组 其中窗口是一个范围 ...
随机推荐
- 我们的团队-IT梦想队
IT梦想队 队长:李遇塘 队员:王长.周兴荣.朱岭杰.马婧婧 团队宣言: 一匹狼战斗力低,但一群狼的我们无所畏惧!李遇塘http://www.cnblogs.com/Liyutang/ 王 长htt ...
- k8s kubectl edit 方式修改 nodeport 的端口
0. 买了一本 每天五分钟玩转 k8s 还有 刚才转帖的blog 里面有一个 kubectl edit 的语法能够在线更改端口号 ,之前一直没弄明白. 刚才做了下实验.发现很好用 这里记录一下. 1. ...
- 用jq获取元素内文本,但不包括其子元素内的文本值的方法
<li id="listItem"> This is some text <span id="firstSpan">First span ...
- C# DataTable Select用法
DataRow[] dr = ds.Tables[0].Select("列名='该列你要查询的值'"); DataRow[] dr = ds.Tables[0].Select(&q ...
- BZOJ1004 HNOI2008Cards(Burnside引理+动态规划)
直接给了一个置换群(当然要自己手动加上不洗牌的情况).考虑求不动点数量即可.对于一个置换,求出所有循环的长度,然后设f[i][x][y]为给前i个循环着色后,用了x张红色卡片.y张绿色卡片的方案数,d ...
- sqlplus执行startup出现ORA-00119,ORA-00132错误
安装好了oracle后,执行如下操作: 执行startup后出现如下错误: ORA-00119: invalid specification for system parameter LOCAL_LI ...
- 【BZOJ4888】[TJOI2017]异或和(树状数组)
[BZOJ4888][TJOI2017]异或和(树状数组) 题面 BZOJ 洛谷 题解 考虑每个位置上的答案,分类讨论这一位是否存在一,值域树状数组维护即可. #include<iostream ...
- 【bzoj2434】 Noi2011—阿狸的打字机
http://www.lydsy.com/JudgeOnline/problem.php?id=2434 (题目链接) 题意 给出一个字符串,$P$表示输出,$B$表示退格.$m$组询问$(x,y)$ ...
- linux(1):VMware虚拟软件下安装centos6.8
前言:Linux是一种自由和开放源代码的类UNIX操作系统,继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统.本人学习Linux已经有一段时间了,从一开始的小白到现在的略有所悟 ...
- SoapUI使用笔记备忘
1.安装好SoapUI后,新建一个REST项目 注意新建REST项目时,需要输入测试站点的地址,即IP+端口 之后点击OK就建立好了项目,但是新项目会默认自带一个根路径访问请求,可以删除(一般没用) ...