C++实现简单的UDP服务端与flag参数解析

时间:2020-04-17
本文章向大家介绍C++实现简单的UDP服务端与flag参数解析,主要包括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.

 
ValueDescription

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