正好有一个大作业关于用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. 20135337朱荟潼 Linux第六周学习总结——进程的描述和进程的创建

    朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 第六周 进程的描述 ...

  2. Daily Scrum – 12/10

    Meeting Minutes 完了了部分页面设计,可能是没有完成的原因,感觉好丑= =: 完成了调整速度的条: 讨论了页面翻转的实现方式,以及可能的简化方式: 进一步整合各个组件: 改进页面上移的按 ...

  3. 项目复审——Beta阶段

    排名原则还是基于这个组到底自己做了多少东西,又借鉴了多少东西,不过其他组的具体情况我也不一定说的清楚,所以只是通过大家的码云和一些了解来评判的.当然,是否发布也是一个重要指标.顺便感叹一句,现在的云平 ...

  4. A总结

    Alpha 答辩总结 评审表 组名 格式 内容 ppt 演讲 答辩 总计 天机组 15 15 14 15 14 73 PMS 16 16 15 15 16 78 日不落战队 16 16 16 15 1 ...

  5. Hyper-V下WINXP无网卡问题解决

  6. Navicat Premium和Navicat for MySQL哪个好用?

    之前在Navicat官网下载了Navicat Premium和Navicat for MySQL使用.Navicat官网产品下载地址:https://www.navicat.com.cn/produc ...

  7. 扩展名为DBF的是什么文件啊?

    扩展名为DBF的文件: .dbf文件是dBase和FoxPro所使用的数据库格式,在没有这两种软件的情况下,可以使用Excel打开文件.在Excel的“打开”文件的对话框中,选择文件类型为“dBase ...

  8. gym101350 c h m

    C. Cheap Kangaroo time limit per test 1.0 s memory limit per test 256 MB input standard input output ...

  9. Java移动文件到另外一个目录

    private void moveTotherFolders(String pathName,String fileName,String ansPath){ String startPath = t ...

  10. 【题解】 Codeforces 919F A Game With Numbers(拓扑排序+博弈论+哈希)

    懒得复制,戳我戳我 Solution: 我感觉我也说不太好,看Awson的题解吧. 说一点之前打错的地方: 连边存的是hash后的数组下标 if(ans[ num( C[a.hash()] , C[b ...