【转载】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"));
}

 

posted @ 2013-06-13 17:34  风雨雪夜  阅读(191)  评论(0编辑  收藏  举报