正好有一个大作业关于用socket实现滑动窗口协议,所以写了一个,模拟接收方与发送方窗口都是2,用两个线程实现。

下面是代码,注释的比较详细了。

socket_udp.h

  1. #include<stdio.h>
  2. #include<Windows.h>
  3. #include<stdlib.h>
  4. #include<time.h>
  5. #include<math.h>
  6. //#include "winsock2.h"
  7. #pragma     comment(lib,"WS2_32.LIB")
  8. #define SWS 2//定义发送窗口
  9. #define RWS 2//定义接收窗口
  10. typedef u_char SwpSeqno;//定义序列号
  11. typedef HANDLE Semaphore;//定义信号量
  12. typedef HANDLE Event;//定义定时器事件
  13. typedef char Msg;//定义消息的类型
  14. typedef struct {
  15. SwpSeqno SeqNum;//帧序号
  16. SwpSeqno AckNum;//已收到确认帧序号
  17. char     Flags;//8 bit 的标志
  18. }SwpHdr;
  19. struct sendQ_slot{
  20. Event timeout;//与发送方相关的超时事件
  21. Msg *msg;//发送的消息
  22. };
  23. struct recvQ_slot{
  24. int recevied; //msg是正确的吗?
  25. Msg *msg;
  26. };
  27. typedef struct {
  28. //发送方状态
  29. SwpSeqno LAR;//最近的收到的ACK序号
  30. SwpSeqno LFS;//最近的发送的帧序号
  31. Semaphore sendWindowNotFull;//信号量,控制滑动窗口的界
  32. SwpHdr hdr;
  33. struct sendQ_slot sendQ[SWS];//发送消息
  34. //接收方状态
  35. SwpSeqno NFE;//期待的下一帧的序号
  36. struct recvQ_slot recvQ[RWS];//接收消息
  37. }SwpState;
  38. //超时线程参数
  39. typedef struct{
  40. int time;
  41. Msg frame[11];
  42. }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

  1. #include"socket_udp.h"
  2. #define HLEN 3//帧头部长度
  3. #define DLEN 8//帧数据长度
  4. #define ALEN 3//ACK帧长度
  5. #define SWP_SEND_TIMEOUT 500//定义超时长度为500ms
  6. #define LINK "127.0.0.1"//定义要发送的对象
  7. #define FLAG_ACK_VALID 'a'//定义ACK帧
  8. #define FLAG_DATA_VALID 'd'//定义数据帧
  9. #define SUCCESS 1;//定义已经成功收到的消息
  10. static void sendSWP(SwpState *state,Msg *frame);//发送函数
  11. static int deliverSWP(SwpState *state,Msg *frame);//接收并返回ACK函数
  12. //发送
  13. static void semWait(Semaphore *sendWindowNotFull);//信号量处理(-1)
  14. static void store_swp_hdr(SwpHdr hdr,char *hbuf);//存储发送的帧头部
  15. static void msgAddHdr(Msg *frame,char *hbuf);//将头部添加到帧上
  16. static void msgSaveCopy(char *msg,Msg *frame);//将消息添加到帧上
  17. static Event evSchedule(Msg *frame,int time);//调用定时器函数
  18. DWORD WINAPI swpTimeout(LPVOID threadtype);//创建定时器线程
  19. static void send_socket(char *addr,Msg *frame,int size);//UDP发送
  20. static void mlisten();//监听数据
  21. static void msend();//发送数据
  22. //接收
  23. static char *msgStripHdr(Msg *frame,int length);//获取帧的头部
  24. static void load_swp_hdr(SwpHdr *hdr,char *hbuf);//帧头部提取字符串
  25. static bool swpInWindow(SwpSeqno AckNum,SwpSeqno LAR,SwpSeqno LFS);//判断收到的帧是否在窗口内
  26. static void evCancel(Event *);//取消超时定时器
  27. static void msgDestroy(Msg *msg);//释放msg空间
  28. static void semSignal(Semaphore *sendWindowNotFull);//信号量处理(+1)
  29. static void prepare_ack(Msg *msg,SwpSeqno n);//组成ACK消息
  30. //全局变量
  31. HANDLE hlisten;
  32. HANDLE hsend;
  33. SwpState *send_state;
  34. Msg *frame;
  35. HANDLE Mutex = CreateMutex(NULL,FALSE,NULL);
  36. void main(){
  37. //模拟滑动窗口接收和发送过程
  38. //初始化SwpState,Msg,数据帧组帧
  39. //启动两个线程,模拟收发
  40. //监听终止
  41. frame=(Msg *)malloc(11*sizeof(Msg));
  42. //初始化消息
  43. //frame="message";//8个字节的数据
  44. //初始化状态
  45. send_state=(SwpState *)malloc(sizeof(SwpState));
  46. send_state->LAR='0';
  47. send_state->LFS='0';
  48. send_state->NFE='0';
  49. send_state->sendWindowNotFull=CreateSemaphore(NULL,SWS,SWS,NULL);
  50. if(send_state->sendWindowNotFull==NULL){
  51. printf("CreateSemaphore error\n",GetLastError());
  52. exit(0);
  53. }
  54. send_state->hdr.SeqNum='0';//3个字节头部
  55. send_state->hdr.AckNum='0';
  56. send_state->hdr.Flags='d';
  57. for(int i=0;i<SWS;i++){
  58. send_state->sendQ[i].msg=(Msg *)malloc(8*sizeof(Msg));
  59. send_state->sendQ[i].msg="message";
  60. send_state->sendQ[i].timeout=NULL;
  61. }
  62. for(int i=0;i<RWS;i++){
  63. send_state->recvQ[i].msg=(Msg *)malloc(8*sizeof(Msg));
  64. send_state->recvQ[i].msg="message";
  65. send_state->recvQ[i].recevied=NULL;
  66. }
  67. //初始化UDP函数
  68. WSADATA wsaData;
  69. if (WSAStartup(MAKEWORD(2,1),&wsaData)){
  70. printf("Winsock initializing fail\n");
  71. WSACleanup();
  72. return;
  73. }
  74. //建立监听线程
  75. hlisten=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) mlisten,NULL,CREATE_SUSPENDED,NULL);
  76. ResumeThread(hlisten);
  77. if(hlisten==NULL){
  78. printf("thread_listen create fail\n");
  79. }
  80. hsend=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) msend,NULL,CREATE_SUSPENDED,NULL);
  81. ResumeThread(hsend);
  82. if(hsend==NULL){
  83. printf("thread_send create fail\n");
  84. }
  85. Sleep(10000);
  86. WSACleanup();
  87. }
  88. static void msend(){
  89. printf("thread_send started\n");
  90. while(1){
  91. sendSWP(send_state,frame);
  92. }
  93. printf("thread_send quit\n");
  94. }
  95. static void sendSWP(SwpState *state,Msg *frame){
  96. struct sendQ_slot *slot;//等待发送
  97. char hbuf[HLEN];//附加在帧头部的字符串
  98. //等待打开发送窗口
  99. semWait(&state->sendWindowNotFull);
  100. WaitForSingleObject(Mutex,INFINITE);
  101. state->hdr.SeqNum=state->LFS++;
  102. printf("send %d\n",state->hdr.SeqNum);
  103. slot=&(state->sendQ[state->hdr.SeqNum % SWS]);
  104. store_swp_hdr(state->hdr,hbuf);
  105. msgAddHdr(frame,hbuf);
  106. msgSaveCopy(slot->msg,frame);
  107. slot->timeout=evSchedule(frame,SWP_SEND_TIMEOUT);
  108. send_socket(LINK,frame,HLEN+DLEN);
  109. ReleaseMutex(Mutex);
  110. }
  111. static int deliverSWP(SwpState *state,Msg *frame){
  112. SwpHdr hdr;
  113. char *hbuf;
  114. hbuf = msgStripHdr(frame,HLEN);
  115. load_swp_hdr(&hdr,hbuf);
  116. if(hdr.Flags == FLAG_ACK_VALID){
  117. //发送方收到一个ACK,处理ACK帧
  118. if(swpInWindow(hdr.AckNum,state->LAR,state->LFS)){
  119. do{
  120. WaitForSingleObject(Mutex,INFINITE);
  121. printf("send get ack %d\n",hdr.AckNum);
  122. struct sendQ_slot *slot;
  123. slot=&state->sendQ[state->LAR++ % SWS];
  124. evCancel(&slot->timeout);
  125. //msgDestroy(slot->msg);
  126. semSignal(&state->sendWindowNotFull);
  127. ReleaseMutex(Mutex);
  128. }while(state->LAR==hdr.AckNum);
  129. }
  130. }
  131. if(hdr.Flags == FLAG_DATA_VALID){
  132. //接收到数据帧,处理数据帧
  133. WaitForSingleObject(Mutex,INFINITE);
  134. struct recvQ_slot *slot;
  135. slot=&state->recvQ[hdr.SeqNum % RWS];
  136. if(!swpInWindow(hdr.SeqNum,state->NFE,state->NFE+RWS-1)){
  137. ReleaseMutex(Mutex);
  138. return SUCCESS;
  139. }
  140. msgSaveCopy(slot->msg,frame);
  141. slot->recevied=TRUE;
  142. if(hdr.SeqNum==state->NFE){
  143. Msg *m=(Msg *)malloc(3*sizeof(Msg));
  144. while(slot->recevied){
  145. //deliver(HLP,&slot->msg)//传向上层
  146. printf("receive get data %d\n",hdr.SeqNum);
  147. printf("%s\n",slot->msg);
  148. //msgDestroy(slot->msg);
  149. slot->recevied=FALSE;
  150. slot=&state->recvQ[state->NFE++ % RWS];
  151. }
  152. prepare_ack(m,state->NFE-1);
  153. send_socket(LINK,m,ALEN);
  154. msgDestroy(m);
  155. }
  156. ReleaseMutex(Mutex);
  157. }
  158. return SUCCESS;
  159. }
  160. static void semWait(Semaphore *sendWindowNotFull){
  161. DWORD   wait_for_semaphore;
  162. wait_for_semaphore  =  WaitForSingleObject(*sendWindowNotFull,-1);
  163. }
  164. static void store_swp_hdr(SwpHdr hdr,char *hbuf){
  165. hbuf[0]=hdr.SeqNum;
  166. hbuf[1]=hdr.AckNum;
  167. hbuf[2]=hdr.Flags;
  168. }
  169. static void msgAddHdr(Msg *frame,char *hbuf){
  170. frame[0]=hbuf[0];
  171. frame[1]=hbuf[1];
  172. frame[2]=hbuf[2];
  173. }
  174. static void msgSaveCopy(char *msg,Msg *frame){
  175. int j=0;
  176. for(int i=3;i<11;i++){
  177. frame[i]=msg[j];
  178. j++;
  179. }
  180. }
  181. static Event evSchedule(Msg *frame,int time){
  182. TimeOutType *timetype=(TimeOutType *)malloc(sizeof(TimeOutType));//超时线程参数
  183. timetype->time=time;
  184. for(int i=0;i<11;i++){
  185. timetype->frame[i]=frame[i];
  186. }
  187. //创建定时器线程
  188. DWORD targetThreadID;
  189. HANDLE Timer=CreateThread(NULL,0,swpTimeout,timetype,CREATE_SUSPENDED,NULL);
  190. ResumeThread(Timer);
  191. if(Timer==NULL){
  192. printf("thread_timeout create fail\n");
  193. }
  194. return Timer;
  195. }
  196. DWORD WINAPI swpTimeout(LPVOID threadtype){
  197. printf("thread_timeout started\n");
  198. TimeOutType *timetype=(TimeOutType *)threadtype;
  199. int time=timetype->time;
  200. Msg *frame;
  201. DWORD result=1;
  202. frame=timetype->frame;
  203. SetTimer(NULL,0,time,NULL);
  204. MSG msg;
  205. BOOL bRet;
  206. while (TRUE)
  207. //该循环捕捉定时器消息
  208. {
  209. bRet = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
  210. if (bRet ==  - 1){
  211. // handle the error and possibly exit
  212. }
  213. else if (bRet && msg.message == WM_TIMER){//定时器
  214. //处理超时事件
  215. printf("send重发%d\n",frame[0]);
  216. send_socket(LINK,frame,HLEN+DLEN);//超时重发
  217. }
  218. else{
  219. TranslateMessage(&msg);
  220. DispatchMessage(&msg);
  221. }
  222. }
  223. printf("thread_timeout_quit");
  224. return result;
  225. }
  226. static void mlisten(){
  227. printf("thread_listen started\n");
  228. SOCKET socket1;
  229. struct sockaddr_in local;
  230. struct sockaddr_in from;
  231. int fromlen =sizeof(from);
  232. local.sin_family=AF_INET;
  233. local.sin_port=htons(8808); ///监听端口
  234. local.sin_addr.s_addr=INADDR_ANY; ///本机
  235. socket1=socket(AF_INET,SOCK_DGRAM,0);
  236. bind(socket1,(struct sockaddr*)&local,sizeof(local));
  237. while (1){
  238. char buffer[11]={0};
  239. if (recvfrom(socket1,buffer,sizeof(buffer),0,(struct sockaddr*)&from,&fromlen)!=SOCKET_ERROR){
  240. deliverSWP(send_state,buffer);
  241. }
  242. }
  243. closesocket(socket1);
  244. printf("listen thread quit\n");
  245. }
  246. static void send_socket(char *addr,Msg *frame,int size){
  247. //UDP发送函数
  248. SOCKET socket1;
  249. struct sockaddr_in server;
  250. int len =sizeof(server);
  251. server.sin_family=AF_INET;
  252. server.sin_port=htons(8808); ///server的监听端口
  253. server.sin_addr.s_addr=inet_addr(LINK); ///server的地址
  254. socket1=socket(AF_INET,SOCK_DGRAM,0);
  255. if (sendto(socket1,frame,sizeof(frame),0,(struct sockaddr*)&server,len)!=SOCKET_ERROR){
  256. }
  257. closesocket(socket1);
  258. }
  259. static char *msgStripHdr(Msg *frame,int length){
  260. char *result=(char *)malloc(sizeof(char));
  261. for(int i=0;i<length;i++){
  262. result[i]=frame[i];
  263. }
  264. return result;
  265. }
  266. static void load_swp_hdr(SwpHdr *hdr,char *hbuf){
  267. hdr->SeqNum=hbuf[0];
  268. hdr->AckNum=hbuf[1];
  269. hdr->Flags=hbuf[2];
  270. }
  271. static bool swpInWindow(SwpSeqno seqno,SwpSeqno min,SwpSeqno max){
  272. SwpSeqno pos,maxpos;
  273. pos=seqno-min;
  274. maxpos=max-min+1;
  275. return pos<maxpos;
  276. }
  277. static void evCancel(Event *thread){
  278. TerminateThread(*thread,0);
  279. printf("thread_timeout quit\n");
  280. }
  281. static void msgDestroy(Msg *msg){
  282. free(msg);
  283. }
  284. static void semSignal(Semaphore *sendWindowNotFull){
  285. if(!ReleaseSemaphore(*sendWindowNotFull,1,NULL)){
  286. printf("ReleseSemphore error\n");
  287. exit(0);
  288. }
  289. }
  290. static void prepare_ack(Msg *m,SwpSeqno n){
  291. //ack组帧
  292. m[0]=NULL;
  293. m[1]=n;
  294. m[2]='a';
  295. }

基于滑动窗口协议写的程序(UDP实现) .的更多相关文章

  1. TCP协议的滑动窗口协议以及流量控制

    参考资料 http://blog.chinaunix.net/uid-26275986-id-4109679.html http://network.51cto.com/art/201501/4640 ...

  2. 面试之路(29)-TCP流量控制和拥塞控制-滑动窗口协议详解

    拥塞: 拥塞发生的主要原因在于网络能够提供的资源不足以满足用户的需求,这些资源包括缓存空间.链路带宽容量和中间节点的处理能力.由于互联网的设计机制导致其缺乏"接纳控制"能力,因此在 ...

  3. 面试连环炮系列(二十):TCP的滑动窗口协议是什么

    TCP的滑动窗口协议是什么 滑动窗口协议,用于网络数据传输时的流量控制,以避免拥塞的发生.该协议允许发送方在停止并等待确认前发送多个数据分组.由于发送方不必每发一个分组就停下来等待确认,因此该协议可以 ...

  4. TCP协议总结--停止等待协议,连续ARQ协议,滑动窗口协议

    前言:在学习tcp三次握手的过程之中,由于一直无法解释tcpdump命令抓的包中seq和ack的含义,就将tcp协议往深入的了解了一下,了解到了几个协议,做一个小结. 先来看看我的问题: 这是用tcp ...

  5. UNIX网络编程——TCP 滑动窗口协议

    什么是滑动窗口协议?     一图胜千言,看下面的图.简单解释下,发送和接受方都会维护一个数据帧的序列,这个序列被称作窗口.发送方的窗口大小由接受方确定,目的在于控制发送速度,以免接受方的缓存不够大, ...

  6. 一篇带你读懂TCP之“滑动窗口”协议

    前言 你现在的努力,是为了以后有更多的选择. 在上一篇文章通过"表白"方式,让我们快速了解网络七层协议了解了网络七层协议. 接下来我们要把重心放在网络传输的可靠性上面.一起来看TC ...

  7. TCP滑动窗口协议

    TCP的首部中​有一个很重要的字段就是16位长的窗口大小,它出现在每一个TCP数据报中,配合32位的确认序号,用于向对端通告本地socket的接收窗口大小.也就是说,如果本地socket发送一个TCP ...

  8. TCP之四:TCP 滑动窗口协议 详解

    滑动窗口机制 滑动窗口协议的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口:同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口.发送窗口和接收窗口的序号的 ...

  9. 流水线机制、滑动窗口协议、GBN、SR

    一.滑动窗口协议 为了解决停等操作的性能问题(发了一个分组之后一直等到确认了这个分组才发下一个),推出了流水线机制,提供资源利用率.就是允许发送方在收到对方的ACK前,发送多个分组 其中窗口是一个范围 ...

随机推荐

  1. Alpha冲刺第10天

    Alpha第10天 1.团队成员 郑西坤 031602542 (队长) 陈俊杰 031602504 陈顺兴 031602505 张胜男 031602540 廖钰萍 031602323 雷光游 0316 ...

  2. Jira 添加自定义字段

    打开添加自定义字段,并选择字段类型 填写名称,并创建 3.选择关联的界面,并更新

  3. Mac OS X使用简介

    一.OS X 版本以大型猫科动物命名 10.0   猎豹(Cheetah) 10.1   美洲狮(Puma) 10.2   美洲虎(Jaguar) 10.3   黑豹(Panther) 10.4   ...

  4. 【大数据】SparkStreaming学习笔记

    第1章 Spark Streaming概述 1.1 Spark Streaming是什么 Spark Streaming用于流式数据的处理.Spark Streaming支持的数据输入源很多,例如:K ...

  5. c++ int转string类型

    std::string int2string(int input){ std::ostringstream ss; //clear string //ss.str(""); //s ...

  6. POJ 1182 食物链 (带权并查集)

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 78551   Accepted: 23406 Description ...

  7. 在PE32位下安装64位2003、2008系统

    步骤 1.进PE(这里是老毛桃为例) 2.将系统(这里windows2008 r2 为例)拷到本地硬盘 3.将ios镜像出来 4.在PE桌面找到 “windows系统安装”,浏览 系统文件  \sou ...

  8. 【刷题】BZOJ 1023 [SHOI2008]cactus仙人掌图

    Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的 ...

  9. Vitrualbox 桥接网卡界面名称未指定、Filters currently installed on the system have reached the limit、不能为虚拟电脑 打开一个新任务

    1. 桥接网卡界面名称未指定 http://wenku.baidu.com/link?url=VFG0hknsDX3VPXQoX5f-g1wUX_LBl-lOj0ZqD222kM31iVCPJKVu3 ...

  10. spring注入时报错::No qualifying bean of type 'xxx.xxMapper'

    做一个小项目,因为有 baseService,所以偷懒就没有写单独的每个xxService接口,直接写的xxServiceImpl,结果在service实现类中注入Mapper的时候,用的 @Auto ...