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就完事了