1 客户端
udp.h
服务器的端口与地址必须要知道,这里我直接初始化,当前只在本机调试所以为"127.0.0.1"
#ifndef UDP_H
#define UDP_H
#include <QObject>
#include <QUdpSocket>
#include "tools.h"
class UDP : public QObject
{
Q_OBJECT
public:
explicit UDP(QObject *parent = nullptr);
private:
void initSocket();
private:
QUdpSocket* m_pRecvSocket;
QUdpSocket* m_pSendSocket;
QByteArray m_BaSend;
const QString m_strAddr = Tools::getHostIpAddress();
const QString m_strServerAddr = "127.0.0.1";
const quint16 m_ServerPort = 10086;
signals:
void signalRecv(QByteArray);
public slots:
void slotRecv();
void slotSend(QByteArray _ba);
};
#endif
udp.cpp
#include "udp.h"
#include <QNetworkDatagram>
#include <QThread>
#include "CommonApproach.h"
UDP::UDP(QObject *parent) : QObject(parent)
{
}
void UDP::initSocket()
{
m_pRecvSocket = new QUdpSocket(this);
m_pRecvSocket->bind(Tools::getRandomPort());
connect(m_pRecvSocket, &QUdpSocket::readyRead,this, &UDP::slotRecv);
}
void UDP::slotRecv()
{
while (m_pRecvSocket->hasPendingDatagrams())
{
QNetworkDatagram datagram = m_pRecvSocket->receiveDatagram();
emit signalRecv(datagram.data());
cout << "Recv son threadId:" << QThread::currentThreadId();
}
}
void UDP::slotSend(QByteArray _ba)
{
m_pSendSocket = new QUdpSocket(this);
m_pSendSocket->writeDatagram(_ba,QHostAddress(m_strServerAddr),m_ServerPort);
}
tools.h
工具类,主要为了随机生成一个当前pc未使用的UDP端口号以及获取本机IP
#ifndef TOOLS_H
#define TOOLS_H
#include <QObject>
#include <QProcess>
#include <QTime>
#include <QNetworkInterface>
class QHostAddress;
class Tools : public QObject
{
Q_OBJECT
public:
explicit Tools(QObject *parent = nullptr);
inline static QList<quint16> getFreePort()
{
QList<quint16> qlist_Port;
QProcess pro;
pro.start("netstat -nao");
pro.waitForStarted();
pro.waitForFinished();
QString str(pro.readAllStandardOutput().data());
QStringList strList = str.split("\n",QString::SkipEmptyParts);
for(int i = 0; i < strList.count(); ++i)
{
QString strTemp(strList[i]);
if(strTemp.contains("UDP") && !strTemp.contains("]:"))
{
strTemp = strTemp.remove(QRegExp("\\s"));
int indexR = strTemp.indexOf("*:*");
int indexL = strTemp.indexOf(":");
strTemp = strTemp.mid(indexL + 1,indexR - indexL - 1);
qlist_Port.push_back(strTemp.toUInt());
}
}
return qlist_Port;
}
inline static quint16 getRandomPort()
{
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
quint16 s = qrand() % 65535;
return s >= 1025 && !getFreePort().contains(s)? s : getRandomPort();
}
inline static QString getHostIpAddress()
{
QList<QHostAddress> list_Addr = QNetworkInterface::allAddresses();
foreach(QHostAddress addr,list_Addr)
{
if(addr.protocol() == QAbstractSocket::IPv4Protocol)
{
return addr.toString();
}
}
return QHostAddress(QHostAddress::LocalHost).toString();
}
signals:
};
#endif
dataprocess.h
test函数暴露给qml,在按下登录按钮的时候调用test,发送嘿嘿嘿 字符串给服务器
#ifndef DATAPROCESS_H
#define DATAPROCESS_H
#include <QObject>
#include <QByteArray>
class UDP;
class QThread;
class DataProcess : public QObject
{
Q_OBJECT
public:
explicit DataProcess(QObject *parent = nullptr);
~DataProcess();
Q_INVOKABLE void test();
private:
void login();
void registerAccount();
void forgetPassword();
void rememberPassword();
private:
UDP *m_pUdp;
QThread *mThread;
signals:
void signalSend(QByteArray);
public slots:
void slotRecv(QByteArray _ba);
};
#endif
dataprocess.cpp
#include "dataprocess.h"
#include "udp.h"
#include <QThread>
#include "CommonApproach.h"
DataProcess::DataProcess(QObject *parent) : QObject(parent)
{
mThread = new QThread(this);
m_pUdp = new UDP;
m_pUdp->moveToThread(mThread);
connect(mThread,&QThread::finished,m_pUdp,&QObject::deleteLater);
connect(this,&DataProcess::signalSend,m_pUdp,&UDP::slotSend);
connect(m_pUdp,&UDP::signalRecv,this,&DataProcess::slotRecv);
mThread->start();
}
DataProcess::~DataProcess()
{
mThread->quit();
mThread->wait();
}
void DataProcess::test()
{
QByteArray ba;
ba.push_back("嘿嘿嘿");
emit signalSend(ba);
}
void DataProcess::slotRecv(QByteArray _ba)
{
cout << "Recv main threadId:" << QThread::currentThreadId();
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "dataprocess.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
DataProcess dp;
engine.rootContext()->setContextProperty("$DP",&dp);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
2 服务器
udp.h
#ifndef UDP_H
#define UDP_H
#include <QObject>
#include <QUdpSocket>
class UDP : public QObject
{
Q_OBJECT
public:
explicit UDP(QObject *parent = nullptr);
private:
private:
QUdpSocket* m_pRcvSck;
QUdpSocket* m_pSndSck;
QByteArray mBaSend;
std::map<int,QString> mmap_Port_Addr;
const quint16 PORT = 10086;
signals:
void signalRecv(QByteArray);
public slots:
void slotRecv();
void slotSend(QByteArray _ba);
};
#endif
udp.cpp
#include "udp.h"
#include <QNetworkDatagram>
#include "CommonApproach.h"
UDP::UDP(QObject *parent)
{
m_pSndSck = new QUdpSocket(this);
m_pRcvSck = new QUdpSocket(this);
m_pRcvSck->bind(this->PORT);
connect(m_pRcvSck, &QUdpSocket::readyRead,this, &UDP::slotRecv);
}
void UDP::slotRecv()
{
while (m_pRcvSck->hasPendingDatagrams())
{
QNetworkDatagram datagram = m_pRcvSck->receiveDatagram();
emit signalRecv(datagram.data());
cout << QString(datagram.data().data());
}
}
void UDP::slotSend(QByteArray _ba)
{
m_pSndSck->writeDatagram(_ba,QHostAddress("127.0.0.1"),this->PORT);
}
process.h
#ifndef PROCESS_H
#define PROCESS_H
#include <QObject>
#include <QByteArray>
class UDP;
class Process : public QObject
{
Q_OBJECT
public:
explicit Process(QObject *parent = nullptr);
Q_INVOKABLE void test();
private:
UDP* m_pUdp;
signals:
protected slots:
void slotRecv(QByteArray _ba);
};
#endif
process.cpp
只是简单框架,所以只有简单的接收,只是为了测试能否通信
#include "process.h"
#include "udp.h"
Process::Process(QObject *parent) : QObject(parent)
{
}
void Process::test()
{
m_pUdp = new UDP;
}
void Process::slotRecv(QByteArray _ba)
{
}
main.cpp
这里直接调用test函数进行初始化,仅测试,后续不会在这里进行调用的
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "process.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
Process pro;
engine.rootContext()->setContextProperty("$PRO",&pro);
pro.test();
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
?结语?
实现了简单的UDP 通信框架,后续会逐渐的加入登录、注册等判定,还有使用数据库存储账号密码等功能
|