转载自:http://blog.youkuaiyun.com/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"));
}