正好有一个大作业关于用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. NetFPGA Demo ——reference_nic_nf1_cml

    NetFPGA Demo --reference_nic_nf1_cml 实验平台 OS:deepin 15.4 开发板:NetFPGA_1G_CML 实验过程 从NetFPGA-1G-CML从零开始 ...

  2. lightgbm原理以及Python代码

    原论文: http://papers.nips.cc/paper/6907-lightgbm-a-highly-efficient-gradient-boosting-decision-tree.pd ...

  3. 11Java网络编程

    十一.网络编程       11.1 网络通信协议 网络通信协议:通信协议是对计算机必须遵守的规则,只有遵守这些规则,计算机之间才能进行通信.这就好比在道路中行驶的汽车一定要遵守交通规则一样,协议中对 ...

  4. java虚拟机的内存划分

    为了提高运算效率,就对空间进行不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式. 一. 1.jvm的内存划分: 区域名称 作用 寄存器 给cpu使用,和我们开发无关 本地方法栈 jv ...

  5. BZOJ2653 middle(二分答案+主席树)

    与中位数有关的题二分答案是很常用的trick.二分答案之后,将所有大于它的看成1小于它的看成-1,那么只需要判断是否存在满足要求的一段和不小于0. 由于每个位置是1还是-1并不固定,似乎不是很好算.考 ...

  6. SP1043 GSS1

    题目链接 简单说就是带修的查询区间最大子段和,用线段树维护即可 对于每个区间,我们肯定要记录它的最大子段和\(v\),但是怎么维护呢? 我们可以记录下从区间左端点开始的最大子段和\(v1\),从右端点 ...

  7. 解题:CF960G Bandit Blues & FJOI 2016 建筑师

    题面1 题面2 两个题推导是一样的,具体实现不一样,所以写一起了,以FJOI 2016 建筑师 的题面为标准 前后在组合意义下一样,现在只考虑前面,可以发现看到的这a个建筑将这一段划分成了a-1个区间 ...

  8. SP422 TRANSP2 - Transposing is Even More Fun——置换群+反演

    挺神仙的置换题 SP422 TRANSP2 - Transposing is Even More Fun 这个博客除了开始举例子别的都是对的: https://blog.csdn.net/Braket ...

  9. requestMapping之地址映射

    转:http://www.cnblogs.com/qq78292959/p/3760560.html 引言: 前段时间项目中用到了RESTful模式来开发程序,但是当用POST.PUT模式提交数据时, ...

  10. final的用法---java基础知识

    Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方法和变量. final类不能被继承,没有子类,final类中的方法默认是final的. final方法 ...