C++ UDP连接方式(QT版)

UdpSocket.h

#pragma once

/*
 * 警告:此模块由于设计的局限,只能用于短消息通讯,无法收发大数据。
 */

#include <QByteArray>
#include <QString>
#include <QObject>
#include <QThread>
#include <QMutex>
#include "Common_global.h"

class COMMON_EXPORT CSocketBase
{
    
    
public:
	virtual void onReadReady() = 0;
	virtual int getfd() = 0;
};

class COMMON_EXPORT CUdpSocket : public QObject ,public CSocketBase
{
    
    
	Q_OBJECT
public:
	CUdpSocket();
	CUdpSocket(int port);
	~CUdpSocket();

public:
	bool open(int port);
	int send(const QByteArray &ar,const QString &addr,int port);
	int recv(QByteArray &ar, QString &addr, int &port);
	bool close();

signals:
	void readyRead();

protected:
	void onReadReady();
	int getfd() {
    
     return m_fd; }

private:
	int m_fd;
	void* m_datalist;
};

UdpSocket.cpp

#include "UdpSocket.h"
#include <winsock2.h>
#include <mstcpip.h>
#include "ModuleMgr.h"
#include <QThread>

//===========================================================================================
class CSocketHandel : protected QThread
{
    
    
protected:
	CSocketHandel();
	~CSocketHandel();

public:
	static CSocketHandel * instance();

	void addSocket(CSocketBase * p);
	void removeSocket(CSocketBase *p);

protected:
	void run();
	int getfd(int *fds, CSocketBase ** base);

protected:
	static void destory();

protected:
	bool m_bRuning;
	bool m_bQuit;

	QMutex m_mutex;
	QList<CSocketBase*> m_socketlist;


private:
	static CSocketHandel * _instance_;
	static bool _bDestoryed_;
};

struct recvData
{
    
    
	QByteArray data;
	QString addr;
	int port;

	recvData() :port(0) {
    
    };
	recvData(char * buffer, int szie, const QString &addr_s, int port_s) {
    
    
		data.append(buffer, szie);
		addr = addr_s;
		port = port_s;
	}
};

class QDataQeue
{
    
    
public:
	QDataQeue() {
    
    };
	~QDataQeue() {
    
    };

	bool isEmpty();
	int get(QByteArray &ar,QString &addr,int &port);
	void add(char * buffer,int szie,const QString &addr,int port);
private:
	QList<recvData> m_datalist;
	QMutex m_mutex;
};

bool QDataQeue::isEmpty()
{
    
    
	return m_datalist.isEmpty();
}

int QDataQeue::get(QByteArray &ar, QString &addr, int &port)
{
    
    
	QMutexLocker locker(&m_mutex);
	if (m_datalist.size() > 0)
	{
    
    
		recvData &d = m_datalist.front();

		int n = d.data.size();
		ar = d.data;
		addr = d.addr;
		port = d.port;

		m_datalist.pop_front();
		return n;
	}

	return 0;
}

void QDataQeue::add(char * buffer, int szie, const QString &addr, int port)
{
    
    
	QMutexLocker locker(&m_mutex);
	if (m_datalist.size() > 2000)m_datalist.pop_front();
	m_datalist.append(recvData(buffer, szie, addr, port));
}
//====================================================================================

CUdpSocket::CUdpSocket():m_fd(-1)
{
    
    
	m_datalist = new QDataQeue();
}

CUdpSocket::CUdpSocket(int port):m_fd(-1)
{
    
    
	m_datalist = new QDataQeue();
	open(port);
}

CUdpSocket::~CUdpSocket()
{
    
    
	if (m_fd != -1)close();
	QDataQeue * datalist = (QDataQeue*)m_datalist;
	if (datalist)delete datalist;
}

bool CUdpSocket::open(int port)
{
    
    
	m_fd = socket(AF_INET, SOCK_DGRAM, 0);                    //建立套接字
	if (m_fd == INVALID_SOCKET)return false;

	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(port);
	int s = bind(m_fd, (sockaddr*)&addrSrv, sizeof(SOCKADDR));//绑定套接字
	if (0 != s)
	{
    
    
		closesocket(m_fd);
		return false;
	}

	//struct timeval timeout = { 0,nTimeout * 1000 };
	int timeout = 3000;
	setsockopt(m_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
	setsockopt(m_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));

	u_long iMode = 1;//非阻塞模式
	ioctlsocket(m_fd, FIONBIO, &iMode);

	CSocketHandel *p = CSocketHandel::instance();
	if (p)p->addSocket(this);

	return true;
}

int CUdpSocket::send(const QByteArray &ar, const QString &addr, int port)
{
    
    
	SOCKADDR_IN addrSock;
	addrSock.sin_addr.S_un.S_addr = inet_addr(addr.toLocal8Bit().data());
	addrSock.sin_family = AF_INET;
	addrSock.sin_port = htons(port);

	int n = ::sendto(m_fd, ar.data(), ar.size(),0, (sockaddr*)&addrSock,sizeof(SOCKADDR_IN));
	if (n > 0)return n;

	return 0;
}

int CUdpSocket::recv(QByteArray &ar, QString &addr, int &port)
{
    
    
	QDataQeue * datalist = (QDataQeue*)m_datalist;
	if (datalist)
	{
    
    
		return datalist->get(ar, addr, port);
	}

	return 0;
}

bool CUdpSocket::close()
{
    
    
	CSocketHandel *p = CSocketHandel::instance();
	if (p)p->removeSocket(this);
	::closesocket(m_fd);
	m_fd = -1;

	return true;
}

void CUdpSocket::onReadReady()
{
    
    
	SOCKADDR_IN addrSock;
	memset(&addrSock, 0, sizeof(SOCKADDR_IN));
	int len = sizeof(SOCKADDR_IN);

	char buffer[4096];
	memset(buffer, 0, 4096);
	int n = ::recvfrom(m_fd, buffer, 4096, 0, (sockaddr*)&addrSock, &len);
	if (n > 0)
	{
    
    
		
		QString addr = inet_ntoa(addrSock.sin_addr);
		int port = ntohs(addrSock.sin_port);

		QDataQeue * datalist = (QDataQeue*)m_datalist;
		if (datalist)
		{
    
    
			datalist->add(buffer, n, addr, port);
		}

		emit readyRead();
	}
}

//===============================================================================
CSocketHandel * CSocketHandel::_instance_ = NULL;
bool CSocketHandel::_bDestoryed_ = false;
//===============================================================================
CSocketHandel::CSocketHandel()
	:m_bRuning(false), m_bQuit(false)
{
    
    
	this->start();
}

CSocketHandel::~CSocketHandel()
{
    
    
	if (m_bRuning)
	{
    
    
		m_bQuit = true;
		while (m_bRuning)QThread::msleep(100);
	}
}

void CSocketHandel::addSocket(CSocketBase * p)
{
    
    
	m_mutex.lock();
	m_socketlist.append(p);
	m_mutex.unlock();
}

void CSocketHandel::removeSocket(CSocketBase *p)
{
    
    
	m_mutex.lock();
	m_socketlist.removeAll(p);
	m_mutex.unlock();
}

CSocketHandel * CSocketHandel::instance()
{
    
    
	if (!_instance_)
	{
    
    
		if (!_bDestoryed_)
		{
    
    
			_instance_ = new CSocketHandel();
			AtExit(CSocketHandel::destory);
		}
	}

	return _instance_;
}

void CSocketHandel::run()
{
    
    
	m_bRuning = true;
	fd_set readfds;
	int fds[64];
	CSocketBase * base[64];
	struct timeval timeout = {
    
     3,0 };

	while (!m_bQuit)
	{
    
    
		FD_ZERO(&readfds);
		memset(fds, 0, 64 * sizeof(int));
		memset(base, 0, 64 * sizeof(CSocketBase*));

		int maxfd = 0;
		int n = getfd(fds, base);
		for (int i = 0; i < n; i++)
		{
    
    
			FD_SET(fds[i], &readfds);
			if (fds[i] > maxfd)maxfd = fds[i];
		}

		int res = select(n, &readfds, NULL, NULL, &timeout);
		if (res > 0)
		{
    
    
			for (int i = 0; i < n; i++)
			{
    
    
				if (FD_ISSET(fds[i], &readfds))
				{
    
    
					base[i]->onReadReady();
				}
			}
		}
	}

	m_bRuning = false;
}

int CSocketHandel::getfd(int *fds, CSocketBase ** base)
{
    
    
	QMutexLocker locker(&m_mutex);

	int n = 0;
	QList<CSocketBase*>::iterator it = m_socketlist.begin();
	for (;it != m_socketlist.end(); ++it)
	{
    
    
		int fd = (*it)->getfd();
		if (fd != -1)
		{
    
    
			fds[n] = fd;
			base[n] = *it;
			n++;
		}
	}

	return n;
}

void CSocketHandel::destory()
{
    
    
	if (_instance_)
	{
    
    
		delete _instance_;
		_bDestoryed_ = true;
	}
}

猜你喜欢

转载自blog.csdn.net/Liang_ming_/article/details/131656762