⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 一个简单的udp server实现.txt

📁 一个简单的UDPServer实现
💻 TXT
字号:
一个简单的UDP Server实现

作者:武乃辉



一、思路
1、建立接收socket,将socket和指定的端口绑定
2、创建接收线程,在线程中调用ioctlsocket()判断是否接收到数据,接收到数据时调用OnReceive()(类似CSocket中的OnReceive())
3、在OnReceive中申请空间调用recvfrom接收数据
4、建立发送socket,和INADDR_ANY绑定
5、调用sendto发送数据
二、本代码直接使用socket API实现UDP通讯 
相关的函数有:
WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);//初始化socket库
WSACleanup();//释放socket库
socket(int af,int type,int protocol); //建立socket
setsockopt(SOCKET s,int level,int optname,const char FAR * optval,int optlen);//设置socket或者协议的属性
bind(SOCKET s,const struct sockaddr FAR * name,int namelen);//地址和socket绑定
sendto(SOCKET s,const char FAR * buf,int len,int flags,const struct sockaddr FAR * to,int tolen);//发送消息
ioctlsocket(SOCKET s,long cmd,u_long FAR * argp);//获取socket状态,可以获取socket缓冲中数据长度,利用这个函数可以实现类似CSocket中的OnReceive()函数(在接收数据之前调用)
recvfrom(SOCKET s,char FAR * buf,int len,int flags,struct sockaddr FAR * from,int FAR * fromlen);//接收数据

三、代码说明
1、UDPServer.h和UDPServer.cpp是实现类CUDPServer的头文件和实现文件,udpdemo.cpp是演示程序
2、编译环境在win2000 vc6.0下编译通过
3、编译时需要在vc的project的setting中连接Ws2_32.lib库


// UDPServer.h: interface for the CUDPServer class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(UDPSERVER_H_INCLUDED_)
#define UDPSERVER_H_INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <Winsock2.h>   // Ws2_32.lib
#define CLOSE_SOCKET(X) if(X!=INVALID_SOCKET){closesocket(X);X=INVALID_SOCKET;}
class CUDPServer  
{
private:
	char m_szLocalIP[20];
	char m_szHostName[30];
	int  m_RecvPort;
	char m_szRemoteIP[20];
	int  m_RemotePort;
	HANDLE m_RecvThread;
	DWORD  m_ThreadID;
private:
	void InitMemberVariable();
public:
	SOCKET m_SckRecive;
	SOCKET m_SckSend;
	bool m_bReciveFlag;
	CUDPServer();
	virtual ~CUDPServer();
	void Initialize();
	void Destory();
	//初始化socket lib
	bool InitSocketLib(WORD wVersion=0x0202);
	void CleanSocketLib();
	//创建发送socket
	bool CreateSendSocket();
	//创建接收socket
	bool CreateRecvSocket(int RecvPort=9527);
	//发送
	int SendMsg(char * szBuf,int length,char * szremoteIP=NULL,int port=0);
	//启动接收线程
	bool StartRecv();
	//停止接收线程
	bool StopRecv();
	//接收线程函数,
	static DWORD WINAPI ReceiveThread(LPVOID lpParameter);   // 线程函数

	//当有数据时,调用OnReceive,length表示数据长度
	void OnReceive(long length);
	static DWORD WINAPI OnReceiveThread(LPVOID lpParameter);   // 线程函数
};

#endif // !defined(UDPSERVER_H_INCLUDED_)

// UDPServer.cpp: implementation of the CUDPServer class.
//
//////////////////////////////////////////////////////////////////////

#include "UDPServer.h"
#include <stdio.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//********************************************************************
CUDPServer::CUDPServer()
{
	Initialize();
}
//********************************************************************
CUDPServer::~CUDPServer()
{
	Destory();
}
//********************************************************************
void CUDPServer::Initialize()
{
	InitSocketLib(0x0202);
	InitMemberVariable();
}
//********************************************************************
void CUDPServer::Destory()
{
	if(m_bReciveFlag)
	{
		StopRecv();
	}
	CleanSocketLib();
}
//********************************************************************
void CUDPServer::InitMemberVariable()
{
	memset(m_szLocalIP,0,20);
	strcpy(m_szLocalIP,"127.0.0.1");
	memset(m_szHostName,0,30);
	m_RecvPort = 9527;
	m_SckRecive = INVALID_SOCKET;
	m_SckSend = INVALID_SOCKET;
	memset(m_szRemoteIP,0,20);
	strcpy(m_szRemoteIP,"127.0.0.1");
	m_RemotePort = 9527;
	m_RecvThread = NULL;
	m_ThreadID = 0;
	m_bReciveFlag = false;
}
//********************************************************************
bool CUDPServer::InitSocketLib(WORD wVersion)
{
	WSADATA wsd;
	int ret = WSAStartup(wVersion,&wsd);
	if(ret!=0)
	{
		WSACleanup();
		return false;
	}
	return true;
}
//********************************************************************
void CUDPServer::CleanSocketLib()
{
	WSACleanup();
}
//********************************************************************
//创建发送socket
bool CUDPServer::CreateSendSocket()
{
	int ret;
	bool flag;
	SOCKADDR_IN addr;

	CLOSE_SOCKET(m_SckSend);
	m_SckSend = socket(AF_INET,SOCK_DGRAM,IPPROTO_IP); 
	if(m_SckSend==INVALID_SOCKET)
	{
		return false;
	}
	flag = true;
	//设置允许地址复用
	ret = setsockopt(m_SckSend,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag));
	if(ret!=0)
	{
		CLOSE_SOCKET(m_SckSend);
		return false;
	}
	//绑定
	ZeroMemory(&addr,sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	//addr.sin_port = htons(m_RecvPort);
	//addr.sin_port = m_RecvPort;
	ret = bind(m_SckSend,(struct sockaddr *)&addr,sizeof(addr));
	if(ret!=0)
	{
		CLOSE_SOCKET(m_SckSend);
		return false;
	}
	return true;
}
//********************************************************************
//创建接收socket
bool CUDPServer::CreateRecvSocket(int RecvPort)
{
	int ret;
	bool flag;
	SOCKADDR_IN addr;

	CLOSE_SOCKET(m_SckRecive);
	m_RecvPort = RecvPort;
	//创建socket
	m_SckRecive = socket(AF_INET,SOCK_DGRAM,IPPROTO_IP); 
	if(m_SckRecive==INVALID_SOCKET)
	{
		return false;
	}
	flag = true;
	//设置允许地址复用
	ret = setsockopt(m_SckRecive,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag));
	if(ret!=0)
	{
		CLOSE_SOCKET(m_SckRecive);
		return false;
	}
	/*const int routenum = 10;
	ret = setsockopt(m_SckMultiCastSend,IPPROTO_IP,IP_MULTICAST_TTL,(char*)&routenum,sizeof(routenum));
	if(ret!=0)
	{
		CLOSE_SOCKET(m_SckMultiCastSend);
		return false;
	}
	const int loopback = 1; //禁止回馈
	ret = setsockopt(m_SckMultiCastSend,IPPROTO_IP,IP_MULTICAST_LOOP,(char*)&loopback,sizeof(loopback));
	if(ret!=0)
	{
		CLOSE_SOCKET(m_SckMultiCastSend);
		return false;
	}
	flag=true;
	//设置该套接字为广播类型,
	setsockopt(m_SckMultiCastSend,SOL_SOCKET,SO_BROADCAST,(char FAR *)&flag,sizeof(flag));*/

	//绑定
	ZeroMemory(&addr,sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	addr.sin_port = htons(m_RecvPort);
	//addr.sin_port = m_MultiCastPort;
	ret = bind(m_SckRecive,(struct sockaddr *)&addr,sizeof(addr));
	if(ret!=0)
	{
		CLOSE_SOCKET(m_SckRecive);
		return false;
	}
	return true;
}
//********************************************************************
//发送
int CUDPServer::SendMsg(char * szBuf,int length,char * szremoteIP,int port)
{
	int ret;
	SOCKADDR_IN addr;
	if(m_SckSend==INVALID_SOCKET)
	{
		return -1;
	}
	if(szremoteIP!=NULL)
	{
		strcpy(m_szRemoteIP,szremoteIP);
		m_RemotePort = port;
	}
	ZeroMemory(&addr,sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(m_szRemoteIP);
	addr.sin_port = htons(m_RemotePort);
	ret = sendto(m_SckSend,szBuf,length,0,(sockaddr *)&addr,sizeof(addr));	
	if(ret == SOCKET_ERROR)
	{
		return -1;
	}
	return ret;	
}
//********************************************************************
//启动接收线程
bool CUDPServer::StartRecv()
{
	if(m_SckRecive==INVALID_SOCKET)
	{
		if(!CreateRecvSocket())
		{
			return false;
		}
	}
	if(m_bReciveFlag)
	{
		return true;
	}
	//m_RecvThread = CreateThread(NULL,0,ReceiveThread,this,0,&m_ThreadID);
	m_RecvThread = CreateThread(NULL,0,OnReceiveThread,this,0,&m_ThreadID);
	
	if(m_RecvThread==NULL)
	{
		return false;
	}
	return true;
}
//********************************************************************
//停止接收线程
bool CUDPServer::StopRecv()
{
	if(!m_bReciveFlag)
	{
		return true;
	}
	CLOSE_SOCKET(m_SckRecive);
	if(m_RecvThread!=NULL)
	{
		WaitForSingleObject(m_RecvThread,INFINITE);
		m_RecvThread = NULL;
		m_ThreadID = 0;
	}
	return true;
}
//********************************************************************
//接收线程函数,
DWORD WINAPI CUDPServer::ReceiveThread(LPVOID lpParameter)
{
	int addr_len;
	struct sockaddr_in addr;
	char szRecBuf[10000];
	int iRecLen;
	CUDPServer * pUDPServer;
	pUDPServer = (CUDPServer *)lpParameter;
	pUDPServer->m_bReciveFlag = true;
	printf("Receive Thread Started.\n");
	/*addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	addr.sin_port = htons(pNetMultiCast->m_MultiCastPort);*/
	while(pUDPServer->m_bReciveFlag)
	{
		 
		addr_len = sizeof(addr);
		iRecLen = recvfrom(pUDPServer->m_SckRecive,szRecBuf,10000,0,(struct sockaddr *)&addr,&addr_len);
		if(iRecLen==SOCKET_ERROR||iRecLen<=0)
		{
			pUDPServer->m_bReciveFlag = false;
		}
		else
		{
			szRecBuf[iRecLen] = 0;
			printf("Receive from %s :%s\n",inet_ntoa(addr.sin_addr),szRecBuf);
		}
	}
	printf("Receive Thread Ended.\n");
	return 0;
}

//********************************************************************
void CUDPServer::OnReceive(long length)
{
	//length 是socket列队中的第一个报文长度
	//在本函数中可以进行业务的处理
	char *pbuf;
	int addr_len,iRecLen;;
	struct sockaddr_in addr;
	pbuf = new char[length+1];
	memset(pbuf,0,length+1);
	addr_len = sizeof(addr);
	iRecLen = recvfrom(m_SckRecive,pbuf,length,0,(struct sockaddr *)&addr,&addr_len);
	if(iRecLen==SOCKET_ERROR||iRecLen<=0||iRecLen!=length)
	{
		printf("Receive Failed!");
	}
	else
	{
		pbuf[length] = 0;
		printf("Receive from %s :%s\n",inet_ntoa(addr.sin_addr),pbuf);
	}
	delete [] pbuf;
	pbuf = NULL;
}
//********************************************************************
DWORD WINAPI CUDPServer::OnReceiveThread(LPVOID lpParameter)
{
	int ret;
	unsigned long lLength;
	CUDPServer * pUDPServer;
	pUDPServer = (CUDPServer *)lpParameter;
	pUDPServer->m_bReciveFlag = true;
	printf("Receive Thread Started.\n");
	while(pUDPServer->m_bReciveFlag)
	{
		ret = ioctlsocket(pUDPServer->m_SckRecive,FIONREAD,&lLength);
		if(ret!=0)
		{
			pUDPServer->m_bReciveFlag = false;
		}
		else
		{
			if(lLength>0)
			{
				pUDPServer->OnReceive(lLength);
			}
		}
	}
	printf("Receive Thread Ended.\n");
	return 0;
}

//udpdemo.cpp
#include <iostream>
#include "UDPServer.h"



using namespace std;

int main(int argc,char *argv)
{
	char szBuf[100];
	CUDPServer pUDPServer;
	cout<<"UDP Demo."<<endl;
	pUDPServer.CreateRecvSocket(9000);
	pUDPServer.CreateSendSocket();
	pUDPServer.StartRecv();
	while(1)
	{
		memset(szBuf,0,100);
		cout<<"Input:";
		cin>>szBuf;
		if(strcmp(szBuf,"quit")==0)
		{
			pUDPServer.StopRecv();
			break;
		}
		pUDPServer.SendMsg(szBuf,strlen(szBuf),"127.0.0.1",9000);
	}
	return 0;
}
	  
四、结束语
欢迎对代码不足之处提出宝贵意见。wnh5@tom.com 
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -