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

最新文章

  1. 解决:eclipse删除工程会弹出一个对话框提示“[project_name]”contains resources that are not in sync with&quot;[workspace_name...\xx\..xx\..\xx]&quot;
  2. 从零自学Hadoop(17):Hive数据导入导出,集群数据迁移下
  3. python web框架——扩展Django&amp;tornado
  4. RAP开发入门-开发笔记
  5. TableViewCell自定义分割线
  6. MVC中System.InvalidOperationException: 传入字典的模型项的类型为“XXX”,但此字典需要类型“XXA”的模型项
  7. NFC(3)Android上的NFC,开启NFC,3种NDEF数据
  8. Nginx NLB 及Redis学习
  9. 淘宝可以传照片搜索商品,verygood.雅客VC多味水果糖
  10. mvc 设置默认页技巧
  11. 设计模式 -- 中介者设计模式 (Mediator Pattern)
  12. Node.js学习 - Event Loop
  13. spring之注解
  14. svn过滤文件配置
  15. 腾讯云中ssL证书的配置安装
  16. 【转载】 github vue 高星项目
  17. 对manacher的一点感性理解
  18. HTTP状态码简单总结
  19. 部署一个基于python语言的web发布环境
  20. C#实现office文档转换为PDF格式

热门文章

  1. DeepID人脸识别算法之三代
  2. 微信小程序动画技巧
  3. Android map转json格式,附上Jackson包下载地址,导入过程
  4. beta 圆桌 3
  5. Docker(二十二)-Docker Swarm常用命令
  6. Win2008r2 由ESXi 转换到 HyperV的处理过程
  7. button 和 submit 的区别
  8. 【Luogu1344】追查坏牛奶(最小割)
  9. 修改docker镜像和容器的存放路径
  10. 01-go语言开始-HelloWorld