基于滑动窗口协议写的程序(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前,发送多个分组 其中窗口是一个范围 ...
随机推荐
- Linux内核读书笔记第二周
什么是系统调用 简单来说,系统调用就是用户程序和硬件设备之间的桥梁.用户程序在需要的时候,通过系统调用来使用硬件设备. 系统调用的存在,有以下重要的意义: 1)用户程序通过系统调用来使用硬件,而不用关 ...
- RYU 的选择以及安装
RYU 的选择以及安装 由于近期的项目需求,不得已得了解一下控制器内部发现拓扑原理,由于某某应用中的控制器介绍中使用的RYU,所以打算把RYU装一下试试.出乎意料的是,RYU竟是我之前装过最最轻便的控 ...
- js弹出层学习
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- [转帖]Application Request Route实现IIS Server Farms集群负载详解
Application Request Route实现IIS Server Farms集群负载详解 https://www.cnblogs.com/knowledgesea/p/5099893.ht ...
- js保留两位小数方法总结
js保留两位小数方法总结 最近在做结算系统,经常需要用到金额保留两位小数,刚开始我一直用的是Angular中的过滤器number |2,但是,这无法满足我的需求.问题是,当用户离开文本框时,我需要将用 ...
- 【BZOJ1432】[ZJOI2009]Function(找规律)
[BZOJ1432][ZJOI2009]Function(找规律) 题面 BZOJ 洛谷 题解 这...找找规律吧. #include<iostream> using namespace ...
- GO内存管理
TMalloc模型 http://www.360doc.com/content/16/0811/09/14513665_582407916.shtml http://blog.csdn.net/cho ...
- jQuery获取radio选中后的文字
原文链接:http://blog.csdn.net/zhanyouwen/article/details/51393216 jQuery获取radio选中后的文字转载 2016年05月13日 10:3 ...
- linux查看进程的线程数
top -H -p $PID #查看对应进程的那个线程占用CPU过高 1.top -H 手册中说:-H : Threads toggle 加上这个选项启动top,top一行显示一个线程.否则,它一行 ...
- java基础基础总结----- String