C++实现简单的UDP服务端与flag参数解析
给公司测试写了个简单的Udp服务端测试接口, 写的时候感觉有很多魔数, 到msdn上查了一些资料, 做一个简单记录, 如有错误疏漏, 欢迎指正
先贴代码
1 #include <iostream> 2 #include <string> 3 4 #include <time.h> 5 6 #include <WinSock2.h> 7 8 #pragma comment(lib,"ws2_32.lib") 9 10 static int g_iPause; 11 12 #define APP_END std::cin >> g_iPause; return 13 #define _MAX_LEN 2048 14 #define _SOCK_ADDR_LEN sizeof(SOCKADDR) 15 #define _STRING_EQUAL 0 16 #define _WSASTARTUP_SUCCESS 0 17 18 void main() 19 { 20 WORD wVerRes; 21 WSADATA wsaData; 22 23 wVerRes = WINSOCK_VERSION; 24 25 if (_WSASTARTUP_SUCCESS != WSAStartup(wVerRes, &wsaData)) 26 { 27 std::cout << "!!!WSAStartup failure" << std::endl; 28 APP_END; 29 } 30 31 //WINSOCK_VERSION展开后是MAKEWORD(2,2),这里要比对上 32 if ((2 != LOBYTE(wsaData.wVersion)) || (2 != HIBYTE(wsaData.wVersion))) 33 { 34 std::cout << "!!!Incorrect Version" << std::endl; 35 WSACleanup(); 36 APP_END; 37 } 38 39 SOCKET sockUdpSrv = socket(AF_INET, SOCK_DGRAM, 0); 40 SOCKADDR_IN addrSrv; 41 addrSrv.sin_family = AF_INET; 42 addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); 43 addrSrv.sin_port = htons(8888); 44 45 if (SOCKET_ERROR == bind(sockUdpSrv, (SOCKADDR*)&addrSrv, _SOCK_ADDR_LEN)) 46 { 47 std::cout << "!!!bind Error" << std::endl; 48 closesocket(sockUdpSrv); 49 WSACleanup(); 50 APP_END; 51 } 52 53 char *recvBuf = new char[_MAX_LEN]; 54 char *sendBuf = new char[_MAX_LEN]; 55 memset(recvBuf, 0, _MAX_LEN); 56 memset(sendBuf, 0, _MAX_LEN); 57 58 SOCKADDR_IN addrClient; 59 int iFromLen = _SOCK_ADDR_LEN; 60 61 std::cout << "udp server is running..." << std::endl; 62 while (true) 63 { 64 //接收 65 if (SOCKET_ERROR == recvfrom(sockUdpSrv, recvBuf, _MAX_LEN, 0, (SOCKADDR*)&addrClient, &iFromLen)) 66 { 67 continue; 68 } 69 70 //时间戳 71 time_t sys_time = time(NULL); 72 std::string sTime_label = asctime(gmtime(&sys_time)); 73 sTime_label[sTime_label.length() - 1] = '\0'; 74 75 //客户端ip地址 76 std::string sClient_ip = inet_ntoa(addrClient.sin_addr); 77 78 std::cout << sTime_label 79 << " recv msg from " 80 << sClient_ip 81 << " : " 82 << recvBuf 83 << std::endl; 84 85 memcpy(sendBuf, recvBuf, _MAX_LEN); 86 87 sendto(sockUdpSrv, sendBuf, _MAX_LEN, 0, (SOCKADDR*)&addrClient, _SOCK_ADDR_LEN); 88 89 if (0 == strcmp(recvBuf, "stop")) 90 { 91 break; 92 } 93 94 memset(recvBuf, 0, _MAX_LEN); 95 memset(sendBuf, 0, _MAX_LEN); 96 } 97 98 delete recvBuf; 99 delete sendBuf; 100 recvBuf = nullptr; 101 sendBuf = nullptr; 102 closesocket(sockUdpSrv); 103 WSACleanup(); 104 105 APP_END; 106 }
主要让我迷惑的地方是recv和send的第四个参数flag, 查了下msdn, 描述如下:
The flags parameter can be used to influence the behavior of the function invocation beyond the options specified for the associated socket. The semantics of the recvfrom function are determined by the socket options and the flags parameter. The following table shows the values can be used to construct the flags parameter. The bitwise OR operator is applied to these values.
Value | Description |
---|---|
MSG_PEEK |
Peeks at the incoming data. The data is copied into the buffer but is not removed from the input queue, and the function returns the number of bytes currently pending to receive. |
MSG_OOB |
Processes OOB data. (See section DECnet Out-Of-band data for a discussion of this topic.) |
MSG_DONTROUTE |
Specifies that the data should not be subject to routing. A Windows Sockets service provider can choose to ignore this flag. |
这里我把recvfrom和sendto的flag可选参数合并了一下, MSG_PEEK和MSG_OOB是recvfrom的可选参数, MSG_DONTROUTE是sendto的可选参数
根据msdn的描述flag参数可以用来控制recv或者send函数的行为, 一般填0就是默认的收发, 没其它影响
这里我查阅了一下WinSock2.h, 头文件里对于flag的可选参数定义如下
这里仅对上面表格里的三个参数做个简单翻译
MSG_PEEK : 接收到数据之后不清空socket的缓冲区, 而是累计起来. 可以理解成, flag = 0时, 缓冲区是 = 操作, flag = MSG_PEEK时, 缓冲区是 += 操作
MSG_OOB : 可以处理OOB数据, OOB数据是传输层的一个数据概念, 具体百度一下吧
MSG_DONTROUTE : 发送数据时不使用路由表查找, 这个可能在某些特殊情况下, 没有具体研究
总结一下就是, flag参数填0就完事了
原文地址:https://www.cnblogs.com/TssiNG-Z/p/12718745.html
- CRM, C4C和Hybris的工作流简介
- 想进大厂?50个多线程面试题,你会多少?(一)
- golang 几种字符串的连接方式
- Go Template学习笔记
- Go语言实现控制台贪吃蛇
- 容灾半自动化的实现思路(二) (r7笔记第93天)
- Go 谚语
- DBA和开发同事的一些代沟(五) (r7笔记第92天)
- 55. 上传文件(Web版) | 厚土Go学习笔记
- ASM无法启动的问题分析(一)(r7笔记第87天)
- 54. 心跳的实现 | 厚土Go学习笔记
- 53. Socket服务三次握手的示例 | 厚土Go学习笔记
- 使用Beego+Swagger构建更好的API服务
- ASM无法启动的问题分析(二)(r7笔记第88天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- laravel5.6框架操作数据curd写法(查询构建器)实例分析
- PHP基于timestamp和nonce实现的防止重放攻击方案分析
- 怎么在 Linux 中查找一个命令或进程的执行时间
- laravel5.6 框架邮件队列database驱动简单demo示例
- php layui实现前端多图上传实例
- 解决Centos7下crontab+shell脚本定期自动删除文件问题
- PHP使用ajax的post方式下载excel文件简单示例
- laravel邮件发送的实现代码示例
- php curl发送请求实例方法
- ubuntn备份办法总结(四种)
- PHP中散列密码的安全性分析
- php的RSA加密解密算法原理与用法分析
- PHP实现微信提现(企业付款到零钱)
- centos7下rsync+crontab定期同步备份
- php抽象类和接口知识点整理总结