【转载】UDP 通讯代码
转载自:http://blog.csdn.net/91program/article/details/6311605
在使用 RAS使用拨号网络拨号的类 建立 TCP/IP后,接下来是通过 TCP/UDP 进行数据的传输。
下面是使用 UDP 的例子,分为头文件和源代码
头文件zhUDPCE.h :
// UDP.h: interface for the CZhUDP class. // ////////////////////////////////////////////////////////////////////// #ifndef _ZH_DUP_CE_H_ #define _ZH_DUP_CE_H_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "WinSock.h" #pragma pack(push,1) //UDP客户端发送错误回调函数 typedef void (CALLBACK *ONZhUDPERROR)(CWnd *,int); //UDP客户端接收数据回调函数 typedef void (CALLBACK *ONZhUDPRECV)(CWnd *,char *buf,int bufLen,sockaddr *); class CZhUDP { public: CZhUDP(); virtual ~CZhUDP(); public: DWORD Open(CWnd *pWnd,int localPort, LPCTSTR remoteHost ,int remotePort); DWORD Close(void); bool SendData(const char *pBuf,int len); BOOL IsSocketOpen(void); // UDP 错误事件 ONZhUDPERROR m_OnUdpError; // UDP 数据接收事件 ONZhUDPRECV m_OnUdpRecv; private: SOCKET m_UDPSocket; struct sockaddr_in m_RemoteAddr; // 存储远程通讯地址 HANDLE m_ExitThreadEvent; // 线程退出事件 CWnd *m_pOwnerWnd; // 存储父窗体句柄 BOOL m_bIsOpen; static UINT RecvThread(LPVOID lparam); }; #pragma pack(pop) #endif
源文件zhUDPCE.cpp :
// UDP.cpp: implementation of the CZhUDP class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "zhUDPCE.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif #define ZHUDP_BUFFER_SIZE 1024 ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CZhUDP::CZhUDP() { m_bIsOpen = FALSE; } CZhUDP::~CZhUDP() { } /* * 功能:打开UDP通讯端口 * 返回值:1代表成功;-1,-2,-3等都代表失败 */ DWORD CZhUDP::Open(CWnd* pWnd, // 父窗体指针 int localPort, // 远程UDP端口 LPCTSTR remoteHost, // 远程IP地址 int remotePort) // 远程UDP端口 { WSADATA wsa; m_pOwnerWnd = pWnd; if(WSAStartup(MAKEWORD(1,1),&wsa) != 0) { return -1; } // 创建UDP套接字 m_UDPSocket = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if(INVALID_SOCKET == m_UDPSocket) { return -2; } SOCKADDR_IN localAddr; localAddr.sin_family = AF_INET; localAddr.sin_port = htons(localPort); localAddr.sin_addr.s_addr=INADDR_ANY; // 绑定地址 if(bind(m_UDPSocket,(sockaddr*)&localAddr,sizeof(localAddr)) != 0) { return -3; } // 设置非堵塞通讯 DWORD wCmdParam = 1; ioctlsocket(m_UDPSocket,FIONBIO,&wCmdParam); // 创建一个线程退出事件 m_ExitThreadEvent = CreateEvent(NULL,TRUE,FALSE,NULL); // 创建通讯线程 AfxBeginThread(RecvThread,this); m_RemoteAddr.sin_family = AF_INET; m_RemoteAddr.sin_port = htons(remotePort); // 此处要将双字节转换成单字节 char ansiRemoteHost[255]; ZeroMemory(ansiRemoteHost,255); WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,remoteHost,wcslen(remoteHost),ansiRemoteHost,wcslen(remoteHost),NULL,NULL); m_RemoteAddr.sin_addr.s_addr=inet_addr(ansiRemoteHost); m_bIsOpen = TRUE; return 1; } /* * 功能:关闭UDP通讯端口 * 返回值:1代表成功;-1,-2等都代表失败 */ DWORD CZhUDP::Close(void) { m_bIsOpen = FALSE; // 设置通讯线程退出事件,通知线程退出 SetEvent(m_ExitThreadEvent); Sleep(1000); CloseHandle(m_ExitThreadEvent); if(closesocket(m_UDPSocket) == SOCKET_ERROR) { return -1; } // 释放socket资源 if(WSACleanup() == SOCKET_ERROR) { return -2; } return 1; } /* * 功能:发送数据 * 返回值:发送成功代表实际发送的字节数,否则返回-1 */ bool CZhUDP::SendData(const char *pBuf, // 缓冲区数据 int len) // 缓冲数据长度 { int nBytes = 0; int nErrorCode = 0; nBytes = sendto(m_UDPSocket,pBuf,len,0,(sockaddr*)&m_RemoteAddr,sizeof(m_RemoteAddr)); if(SOCKET_ERROR == nBytes) { nErrorCode = WSAGetLastError(); m_OnUdpError(m_pOwnerWnd,nErrorCode); return false; } return true; } /* * 功能:接收线程函数 * 返回值:无意义。 */ UINT CZhUDP::RecvThread(LPVOID lparam) // 指传进线程的参数 { CZhUDP *pSocket; pSocket = (CZhUDP *)lparam; fd_set fdRead; int ret = 0; TIMEVAL tvTimeout; char *pcRecvBuf = NULL; SOCKADDR_IN tmpAddr; int tmpRecvLen = 0; int recvLen = 0; int iErrorCode = 0; char *pcRecvedBuf = NULL; int recvedBufLen = 0; tvTimeout.tv_sec = 1; tvTimeout.tv_usec = 0; while(TRUE) { // 收到退出事件,结束线程 if(WaitForSingleObject(pSocket->m_ExitThreadEvent,0) == WAIT_OBJECT_0) { break; } // 初始化 set FD_ZERO(&fdRead); // 将 pSocket->m_UDPSocket 套接字添加到集合中 FD_SET(pSocket->m_UDPSocket,&fdRead); // 判断套接字I/O状态 ret = select(0,&fdRead,NULL,NULL,&tvTimeout); if(SOCKET_ERROR == ret) { iErrorCode = WSAGetLastError(); pSocket->m_OnUdpError(pSocket->m_pOwnerWnd,iErrorCode); break; } if(ret > 0) { if(FD_ISSET(pSocket->m_UDPSocket,&fdRead)) { tmpAddr.sin_family = AF_INET; tmpAddr.sin_port = htons(pSocket->m_RemoteAddr.sin_port); tmpAddr.sin_addr.s_addr = INADDR_ANY; tmpRecvLen = sizeof(tmpAddr); pcRecvBuf = new char[ZHUDP_BUFFER_SIZE]; pcRecvedBuf = new char[ZHUDP_BUFFER_SIZE]; ZeroMemory(pcRecvBuf,ZHUDP_BUFFER_SIZE); ZeroMemory(pcRecvedBuf,ZHUDP_BUFFER_SIZE); recvLen = recvfrom(pSocket->m_UDPSocket,pcRecvBuf,ZHUDP_BUFFER_SIZE,0,(SOCKADDR *)&tmpAddr,&tmpRecvLen); if(SOCKET_ERROR == recvLen) { iErrorCode = WSAGetLastError(); pSocket->m_OnUdpError(pSocket->m_pOwnerWnd,iErrorCode); break; } else if(0 == recvLen) { iErrorCode = WSAGetLastError(); pSocket->m_OnUdpError(pSocket->m_pOwnerWnd,iErrorCode); break; } else { // 此处添加解析程序,将接收到的数据解析后 pSocket->m_OnUdpRecv(pSocket->m_pOwnerWnd,pcRecvBuf,recvedBufLen,(SOCKADDR *)&tmpAddr); delete []pcRecvBuf; delete []pcRecvedBuf; pcRecvBuf = NULL; pcRecvedBuf = NULL; } } } } return 0; } /* * 功能:判断 Socket 状态 */ BOOL CZhUDP::IsSocketOpen(void) { return m_bIsOpen; }
使用示例:
定义
CZhUDP m_ZhUdpCE;
static void CALLBACK OnZhUdpRecv(CWnd *pWnd,char *buf,int nLen,sockaddr *addr);
static void CALLBACK OnZhUdpError(CWnd *pWnd,int nError);
// 建立 UDP 链接 m_ZhUdpCE.m_OnUdpRecv = OnZhUdpRecv; m_ZhUdpCE.m_OnUdpError = OnZhUdpError; DWORD nResult = m_ZhUdpCE.Open(this,m_iLocalPort,m_csRemoteHost,m_iRemotePort); if (nResult <= 0) { RETAILMSG(1,(L"DUPClient,Open UDP failed/r/n")); return; } else { RETAILMSG(1,(L"DUPClient,Open UDP success/r/n")); } // 断开 UDP 链接 if(1 == m_ZhUdpCE.Close()) { RETAILMSG(1,(L"DUPClient,Close UDP success/r/n")); } else { RETAILMSG(1,(L"DUPClient,Close UDP failed/r/n")); }