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 }