UDP 通讯代码

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UDP 通讯代码相关的知识,希望对你有一定的参考价值。

在使用 RAS使用拨号网络拨号的类 建立 TCP/IP后,接下来是通过 TCP/UDP 进行数据的传输。

 下面是使用 UDP 的例子,分为头文件和源代码

 头文件zhUDPCE.h :

 1 // UDP.h: interface for the CZhUDP class.  
 2 //  
 3 //////////////////////////////////////////////////////////////////////  
 4 #ifndef _ZH_DUP_CE_H_  
 5 #define _ZH_DUP_CE_H_  
 6 #if _MSC_VER > 1000  
 7 #pragma once  
 8 #endif // _MSC_VER > 1000  
 9 #include "WinSock.h"  
10 #pragma pack(push,1)  
11 //UDP客户端发送错误回调函数  
12 typedef void (CALLBACK *ONZhUDPERROR)(CWnd *,int);  
13 //UDP客户端接收数据回调函数  
14 typedef void (CALLBACK *ONZhUDPRECV)(CWnd *,char *buf,int bufLen,sockaddr *);  
15 class CZhUDP    
16 {  
17 public:  
18     CZhUDP();  
19     virtual ~CZhUDP();  
20 public:  
21     DWORD Open(CWnd *pWnd,int localPort, LPCTSTR remoteHost ,int remotePort);  
22     DWORD Close(void);  
23     bool SendData(const char *pBuf,int len);  
24     BOOL IsSocketOpen(void);  
25     // UDP 错误事件  
26     ONZhUDPERROR m_OnUdpError;  
27     // UDP 数据接收事件  
28     ONZhUDPRECV  m_OnUdpRecv;  
29 private:  
30     SOCKET m_UDPSocket;  
31     struct sockaddr_in m_RemoteAddr;      // 存储远程通讯地址  
32     HANDLE m_ExitThreadEvent;             // 线程退出事件  
33     CWnd *m_pOwnerWnd;                    // 存储父窗体句柄  
34     BOOL m_bIsOpen;  
35     static UINT RecvThread(LPVOID lparam);  
36 };  
37 #pragma pack(pop)  
38 #endif  

源文件zhUDPCE.cpp :

  1 // UDP.cpp: implementation of the CZhUDP class.  
  2 //  
  3 //////////////////////////////////////////////////////////////////////  
  4 #include "stdafx.h"  
  5 #include "zhUDPCE.h"  
  6 #ifdef _DEBUG  
  7 #undef THIS_FILE  
  8 static char THIS_FILE[]=__FILE__;  
  9 #define new DEBUG_NEW  
 10 #endif  
 11 #define ZHUDP_BUFFER_SIZE 1024  
 12 //////////////////////////////////////////////////////////////////////  
 13 // Construction/Destruction  
 14 //////////////////////////////////////////////////////////////////////  
 15 CZhUDP::CZhUDP()  
 16 {  
 17     m_bIsOpen = FALSE;  
 18 }  
 19 CZhUDP::~CZhUDP()  
 20 {  
 21 }  
 22 /* 
 23  * 功能:打开UDP通讯端口 
 24  * 返回值:1代表成功;-1,-2,-3等都代表失败 
 25 */  
 26 DWORD CZhUDP::Open(CWnd* pWnd,          // 父窗体指针  
 27                    int localPort,       // 远程UDP端口  
 28                    LPCTSTR remoteHost,  // 远程IP地址  
 29                    int remotePort)      // 远程UDP端口  
 30 {  
 31     WSADATA wsa;  
 32       
 33     m_pOwnerWnd = pWnd;  
 34     if(WSAStartup(MAKEWORD(1,1),&wsa) != 0)  
 35     {  
 36         return -1;  
 37     }  
 38       
 39     // 创建UDP套接字  
 40     m_UDPSocket = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);  
 41     if(INVALID_SOCKET == m_UDPSocket)  
 42     {  
 43         return -2;  
 44     }  
 45       
 46     SOCKADDR_IN localAddr;  
 47     localAddr.sin_family = AF_INET;  
 48     localAddr.sin_port = htons(localPort);  
 49     localAddr.sin_addr.s_addr=INADDR_ANY;  
 50       
 51     // 绑定地址  
 52     if(bind(m_UDPSocket,(sockaddr*)&localAddr,sizeof(localAddr)) != 0)  
 53     {  
 54         return -3;  
 55     }  
 56       
 57     // 设置非堵塞通讯  
 58     DWORD wCmdParam = 1;  
 59     ioctlsocket(m_UDPSocket,FIONBIO,&wCmdParam);  
 60     // 创建一个线程退出事件  
 61     m_ExitThreadEvent = CreateEvent(NULL,TRUE,FALSE,NULL);  
 62       
 63     // 创建通讯线程  
 64     AfxBeginThread(RecvThread,this);  
 65       
 66     m_RemoteAddr.sin_family = AF_INET;  
 67     m_RemoteAddr.sin_port = htons(remotePort);  
 68     // 此处要将双字节转换成单字节  
 69     char ansiRemoteHost[255];  
 70     ZeroMemory(ansiRemoteHost,255);  
 71     WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,remoteHost,wcslen(remoteHost),ansiRemoteHost,wcslen(remoteHost),NULL,NULL);  
 72     m_RemoteAddr.sin_addr.s_addr=inet_addr(ansiRemoteHost);  
 73     m_bIsOpen = TRUE;  
 74     return 1;  
 75 }  
 76 /* 
 77  * 功能:关闭UDP通讯端口 
 78  * 返回值:1代表成功;-1,-2等都代表失败 
 79 */  
 80 DWORD CZhUDP::Close(void)  
 81 {  
 82     m_bIsOpen = FALSE;  
 83     // 设置通讯线程退出事件,通知线程退出  
 84     SetEvent(m_ExitThreadEvent);  
 85     Sleep(1000);  
 86     CloseHandle(m_ExitThreadEvent);  
 87     if(closesocket(m_UDPSocket) == SOCKET_ERROR)  
 88     {  
 89         return -1;  
 90     }  
 91       
 92     // 释放socket资源  
 93     if(WSACleanup() == SOCKET_ERROR)  
 94     {  
 95         return -2;  
 96     }  
 97     return 1;  
 98 }  
 99 /* 
100 * 功能:发送数据 
101 * 返回值:发送成功代表实际发送的字节数,否则返回-1 
102 */  
103 bool CZhUDP::SendData(const char *pBuf, // 缓冲区数据  
104                       int len)          // 缓冲数据长度  
105 {  
106     int nBytes = 0;  
107     int nErrorCode = 0;  
108     nBytes = sendto(m_UDPSocket,pBuf,len,0,(sockaddr*)&m_RemoteAddr,sizeof(m_RemoteAddr));        
109     if(SOCKET_ERROR == nBytes)    
110     {         
111         nErrorCode = WSAGetLastError();   
112         m_OnUdpError(m_pOwnerWnd,nErrorCode);  
113         return false;     
114     }  
115     return true;  
116 }  
117 /* 
118  * 功能:接收线程函数 
119  * 返回值:无意义。 
120 */  
121 UINT CZhUDP::RecvThread(LPVOID lparam)  // 指传进线程的参数  
122 {  
123     CZhUDP *pSocket;  
124     pSocket = (CZhUDP *)lparam;  
125     fd_set fdRead;  
126     int ret = 0;  
127     TIMEVAL tvTimeout;  
128     char *pcRecvBuf = NULL;  
129     SOCKADDR_IN tmpAddr;  
130     int tmpRecvLen = 0;  
131     int recvLen = 0;  
132     int iErrorCode = 0;  
133     char *pcRecvedBuf = NULL;  
134     int recvedBufLen = 0;  
135     tvTimeout.tv_sec = 1;  
136     tvTimeout.tv_usec = 0;  
137     while(TRUE)  
138     {  
139         // 收到退出事件,结束线程  
140         if(WaitForSingleObject(pSocket->m_ExitThreadEvent,0) == WAIT_OBJECT_0)  
141         {  
142             break;  
143         }  
144         // 初始化 set  
145         FD_ZERO(&fdRead);  
146           
147         // 将 pSocket->m_UDPSocket 套接字添加到集合中  
148         FD_SET(pSocket->m_UDPSocket,&fdRead);  
149           
150         // 判断套接字I/O状态  
151         ret = select(0,&fdRead,NULL,NULL,&tvTimeout);  
152           
153         if(SOCKET_ERROR == ret)  
154         {  
155             iErrorCode = WSAGetLastError();  
156             pSocket->m_OnUdpError(pSocket->m_pOwnerWnd,iErrorCode);  
157             break;  
158         }  
159           
160         if(ret > 0)  
161         {  
162             if(FD_ISSET(pSocket->m_UDPSocket,&fdRead))  
163             {  
164                 tmpAddr.sin_family = AF_INET;               
165                 tmpAddr.sin_port = htons(pSocket->m_RemoteAddr.sin_port);  
166                 tmpAddr.sin_addr.s_addr = INADDR_ANY;  
167                 tmpRecvLen = sizeof(tmpAddr);  
168                   
169                 pcRecvBuf = new char[ZHUDP_BUFFER_SIZE];  
170                 pcRecvedBuf = new char[ZHUDP_BUFFER_SIZE];  
171                 ZeroMemory(pcRecvBuf,ZHUDP_BUFFER_SIZE);  
172                 ZeroMemory(pcRecvedBuf,ZHUDP_BUFFER_SIZE);  
173                 recvLen = recvfrom(pSocket->m_UDPSocket,pcRecvBuf,ZHUDP_BUFFER_SIZE,0,(SOCKADDR *)&tmpAddr,&tmpRecvLen);   
174                 if(SOCKET_ERROR == recvLen)  
175                 {  
176                     iErrorCode = WSAGetLastError();  
177                     pSocket->m_OnUdpError(pSocket->m_pOwnerWnd,iErrorCode);  
178                       
179                     break;  
180                 }  
181                 else if(0 == recvLen)  
182                 {  
183                     iErrorCode = WSAGetLastError();  
184                     pSocket->m_OnUdpError(pSocket->m_pOwnerWnd,iErrorCode);     
185                       
186                     break;  
187                 }  
188                    
189                 else  
190                 {  
191                     // 此处添加解析程序,将接收到的数据解析后  
192                     pSocket->m_OnUdpRecv(pSocket->m_pOwnerWnd,pcRecvBuf,recvedBufLen,(SOCKADDR *)&tmpAddr);  
193                       
194                     delete []pcRecvBuf;  
195                     delete []pcRecvedBuf;  
196                     pcRecvBuf = NULL;  
197                     pcRecvedBuf = NULL;  
198                 }  
199                   
200             }  
201         }  
202     }  
203     return 0;  
204 }  
205 /* 
206  * 功能:判断 Socket 状态 
207 */  
208 BOOL CZhUDP::IsSocketOpen(void)  
209 {  
210     return m_bIsOpen;  
211 }  

使用示例:

 定义

1 CZhUDP m_ZhUdpCE;
2 static void CALLBACK OnZhUdpRecv(CWnd *pWnd,char *buf,int nLen,sockaddr *addr);
3 static void CALLBACK OnZhUdpError(CWnd *pWnd,int nError);
 1 // 建立 UDP 链接  
 2 m_ZhUdpCE.m_OnUdpRecv = OnZhUdpRecv;  
 3 m_ZhUdpCE.m_OnUdpError = OnZhUdpError;  
 4 DWORD nResult = m_ZhUdpCE.Open(this,m_iLocalPort,m_csRemoteHost,m_iRemotePort);  
 5 if (nResult <= 0)   
 6 {  
 7     RETAILMSG(1,(L"DUPClient,Open UDP failed/r/n"));  
 8     return;  
 9 }  
10 else  
11 {  
12     RETAILMSG(1,(L"DUPClient,Open UDP success/r/n"));  
13 }  
14 // 断开 UDP 链接  
15 if(1 == m_ZhUdpCE.Close())  
16 {  
17     RETAILMSG(1,(L"DUPClient,Close UDP success/r/n"));  
18 }  
19 else  
20 {  
21     RETAILMSG(1,(L"DUPClient,Close UDP failed/r/n"));  
22 }  

 

以上是关于UDP 通讯代码的主要内容,如果未能解决你的问题,请参考以下文章

.Net UDP通讯示例

异常和TCP通讯

Udp客户端与服务通讯

golang代码片段(摘抄)

C# UDP通讯实例

MicroPython ESP32 UDP和TCP数据收发通讯综合实例