一.需要用到的类
QThread和QUDPSocket
.pro文件中需要引入模块
QT += network
常用接口:
1.bool bind(quint16 port = 0, BindMode mode = DefaultForPlatform) ;//绑定端口
2.qint64 writeDatagram(const QByteArray &datagram, const QHostAddress &host, quint16 port);//发送数据
3.void abort() ;//关闭连接
4.qint64 readDatagram(char *data, qint64 maxSize, QHostAddress *address = Q_NULLPTR, quint16 *port = Q_NULLPTR);//读数据
每当有数据接收的时候,QUdpSocket都会发送 readyRead()信号,只需要绑定上槽就能接收到数据。
二.server work类
此类的作用主要实现UDP之间的通信,直接上代码。
//WUDPServerWorker.h
#ifndef WUDPSERVERWORKER_H
#define WUDPSERVERWORKER_H
#include <QObject>
#include <QUdpSocket>
class WUDPServerWorker : public QObject
{
Q_OBJECT
public:
explicit WUDPServerWorker(QObject *parent = nullptr);
~WUDPServerWorker();
public:
//绑定端口
bool bind(qint16 port);
//解绑端口
void unBind();
//发送数据
qint64 sendDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port);
//发送数据
qint64 sendDatagram(const QByteArray &data,const QHostAddress &host, quint16 port);
signals:
//发送UDP数据
void sigReceiveData(const QByteArray &byte);
private slots:
//收到UDP数据
void slotReadyRead();
private:
QUdpSocket *m_udpSocket = nullptr; //UDP socket
};
#endif // WUDPSERVERWORKER_H
/WUDPServerWorker.cpp
#include "WUdpServerWorker.h"
#include <QDebug>
WUDPServerWorker::WUDPServerWorker(QObject *parent)
: QObject(parent)
{
m_udpSocket = new QUdpSocket(this);
connect(m_udpSocket,SIGNAL(readyRead()),this,SLOT(slotReadyRead()));
}
WUDPServerWorker::~WUDPServerWorker()
{
if(m_udpSocket)
{
unBind();
delete m_udpSocket;
}
}
bool WUDPServerWorker::bind(qint16 port)
{
return m_udpSocket->bind(port);
}
void WUDPServerWorker::unBind()
{
if(m_udpSocket)
m_udpSocket->abort();
}
qint64 WUDPServerWorker::sendDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port)
{
return m_udpSocket->writeDatagram(data,len,host,port);
}
qint64 WUDPServerWorker::sendDatagram(const QByteArray &data, const QHostAddress &host, quint16 port)
{
return m_udpSocket->writeDatagram(data,host,port);
}
void WUDPServerWorker::slotReadyRead()
{
//是否还有待读取的传入数据报
while(m_udpSocket->hasPendingDatagrams())
{
QByteArray data;
//返回待读取的数据报的字节数
data.resize(m_udpSocket->pendingDatagramSize());
QHostAddress peerAddr;
quint16 peerPort;
//读取数据报的内容
m_udpSocket->readDatagram(data.data(),data.size(),&peerAddr,&peerPort);
QString port = QString::number(m_udpSocket->localPort());
QString peerStr = port + " *****recieve udp data [From ] +"+peerAddr.toString()+":"+QString::number(peerPort)+"] ";
qDebug()<<peerStr;
emit sigReceiveData(data);
}
}
每当有数据收到后,会调用slotReadyRead()槽函数,然后readDatagram()读取数据,可以知道数据来源的地址和端口号。
三.server类
此类主要作用是让udp在单独线程运行。
//WUDPServer.h
#ifndef WUDPSERVER_H
#define WUDPSERVER_H
#include <QObject>
#include <QThread>
#include <QHostAddress>
#include <QDebug>
class WUDPServerWorker;
class WUDPServer : public QObject
{
Q_OBJECT
public:
explicit WUDPServer(qint16 port = 0,QObject *parent = nullptr);
~WUDPServer();
public:
//发送数据
qint64 sendDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port);
//发送数据
qint64 sendDatagram(const QByteArray &data, const QHostAddress &host, quint16 port);
//开始线程
void start();
private slots:
//收到UDP数据
void slotReceiveUdpData(const QByteArray&);
private:
QThread m_workerThread; //UDP工作线程
WUDPServerWorker *m_work = nullptr; //UDP工作类
};
#endif // WUDPSERVER_H
///WUDPServer.cpp
#include "WUdpServer.h"
#include "WUdpServerWorker.h"
WUDPServer::WUDPServer(qint16 port,QObject *parent)
: QObject(parent)
{
m_work = new WUDPServerWorker;
if(!m_work->bind(port))
{
qDebug()<<"(UdpServer::UdpServer)*****udp listen port ="<<port<<" error";
}
else
{
qDebug()<<"*****udp listen port ="<<port<<" success";
}
m_work->moveToThread(&m_workerThread);
connect(&m_workerThread, &QThread::finished, &m_workerThread,&QObject::deleteLater);
connect(&m_workerThread, &QThread::finished, m_work, &QObject::deleteLater);
connect(m_work,SIGNAL(sigReceiveData(QByteArray)),this,SLOT(slotReceiveUdpData(QByteArray)));
}
WUDPServer::~WUDPServer()
{
m_workerThread.quit();
m_workerThread.wait();
}
qint64 WUDPServer::sendDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port)
{
return m_work->sendDatagram(data,len,host,port);
}
qint64 WUDPServer::sendDatagram(const QByteArray &data, const QHostAddress &host, quint16 port)
{
return m_work->sendDatagram(data,host,port);
}
void WUDPServer::start()
{
m_workerThread.start();
}
void WUDPServer::slotReceiveUdpData(const QByteArray& byte)
{
//处理数据
qDebug()<<byte;
}
在类中创建了一个线程,将WUDPServerWorker对象放在线程中运行,调用moveToThread()方法即可,需要绑定两个槽,
connect(&m_workerThread,&QThread::finished,&m_workerThread,&QObject::deleteLater) connect(&m_workerThread, &QThread::finished, m_work, &QObject::deleteLater);
在线程完成后,释放资源,不但要释放线程本身,还需要释放WUDPServerWorker对象。
在程序退出时需要调用以下方法,优雅的结束线程。
m_workerThread.quit(); m_workerThread.wait();
使用方法:
WUDPServer *server = new WUDPServer(8888,nullptr);
server->start();
四.更多参考
QT UDP通信
QT 多线程?
五.源码
源码包
|