【Qt Quick聊天软件练习】五、udp客户端与服务器简单框架

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:
    /**
     * @brief signalRecv:发射接收信号给数据处理槽函数
     */
    void signalRecv(QByteArray);

public slots:
    /**
     * @brief UDP::slotRecv:接收槽函数
     */
    void slotRecv();
    /**
     * @brief slotSend:发送函数
     * @param _ba:发送数据
     */
    void slotSend(QByteArray _ba);
};

#endif // UDP_H


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);

    /**
     * @brief getFreePort:获取当前已启用的UDP端口列表
     * @return
     */
    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;
    }

    /**
     * @brief getRandomPort:获取一个1025~65535之间的数字作为端口号
     * @return
     */
    inline static quint16 getRandomPort()
    {
        qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
        quint16 s = qrand() % 65535;

        return s >= 1025 && !getFreePort().contains(s)? s : getRandomPort();
    }

    /**
     * @brief getHostIpAddress:获取本机IP
     * @return
     */
    inline static QString getHostIpAddress()
    {
        //获取第一个本主机IPv4地址
        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 // TOOLS_H

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_H

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:
    /**
     * @brief signalRecv:发射接收信号给数据处理槽函数
     */
    void signalRecv(QByteArray);

public slots:
    /**
     * @brief slotRecv:接收槽函数
     */
    void slotRecv();
    /**
     * @brief slotSend:发送函数
     * @param _ba:发送数据
     */
    void slotSend(QByteArray _ba);

};

#endif // UDP_H


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_H

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通信框架,后续会逐渐的加入登录、注册等判定,还有使用数据库存储账号密码等功能

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

非西昂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值