IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 【Qt Quick聊天软件练习】五、udp客户端与服务器简单框架 -> 正文阅读

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

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:56:55  更:2022-03-24 00:57:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:56:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码