使用多线程实现QT UDP接收

使用多线程的方式,实现UDP数据的接收,并将接收到的UDP数据打印到textEdit当中。

今天这个demo主要是使用socket绑定一个固定的IP个端口接收UDP数据,使用moveToThread的方式将UDP的接收放到子线程里面。

废话不多说,直接开始:

步骤1:界面设计,这里其实只需要绑定自己的IP和接收端口就好了,我主要是想要后面接着利用这个demo写其他的东西,所以就多添加了写组件,注意要添加一个textEdit来显示接收到的数据。

步骤二:创建一个ReceiveClass.cpp和ReceiveClass.h来实现咱们的UDP接收class:

ReceiveClass.h

#ifndef RECEIVECLASS_H
#define RECEIVECLASS_H
#include <QObject>
#include <QUdpSocket>


class ReceiveClass : public QObject
{
    Q_OBJECT
public:
    explicit ReceiveClass(QObject *parent = nullptr) : QObject(parent) {}

    void ReceiveSocketInif(QString ip,quint16 port);

    //定义槽函数
public slots:
    void startReceiving();

    //定义信号
signals:
    //UDP接收到数据信号
    void datagramReceived(QByteArray data);
    //日志输出信号
     void UdpRcvLogSingal(const QString& text);

    //定义槽处理函数
private slots:
    void processPendingDatagrams();

private:
    QUdpSocket *socket;
};

#endif // RECEIVECLASS_H

ReceiveClass.cpp

#include "ReceiveClass.h"
bool socketInitFlag = false;


void ReceiveClass::ReceiveSocketInif(QString ip,quint16 port)
{
    QString log = "";
    bool ret = false;
    // 创建QUdpSocket对象
    socket = new QUdpSocket(this);
    QHostAddress IP(ip);
    ret = socket->bind(IP, port);
    if(ret == true)
    {
        socketInitFlag = true;
        log += "Socket初始化成功\n";
    }
    else
    {
        socketInitFlag = false;
        log += "Socket初始化失败\n";
    }
    emit UdpRcvLogSingal(log);
}

void ReceiveClass::startReceiving()
{
    QString log = "";
    //当前socket已经初始化完成
    if((socketInitFlag == true) && (nullptr != socket ))
    {
        connect(socket, &QUdpSocket::readyRead, this, &ReceiveClass::processPendingDatagrams);
    }
    else
    {
        log += "接收socket未初始化未完成\n";
    }
    emit UdpRcvLogSingal(log);
}

//收到数据后完成数据读取连接信号
void ReceiveClass::processPendingDatagrams()
{
    while (socket->hasPendingDatagrams())
            {
                QByteArray datagram;
                datagram.resize(socket->pendingDatagramSize());
                //将信息读取完成
                socket->readDatagram(datagram.data(), datagram.size());
                //传递信号
                emit datagramReceived(datagram);
            }
}


步骤3:在自己的主窗口文件中实现几个槽函数,日志输出槽函数和UDP接收处理槽函数

函数实现

//接收数据槽处理函数
void MainWindow::handleReceivedDatagram(QByteArray data)
{
    QString str = "";
    const uint8_t* receiveBuffer = reinterpret_cast<const uint8_t*>(data.constData());
    for(size_t i=0; i< data.size(); i++)
    {
        //将接收到的数据按照16进制的方式显示
        str += QString("%1").arg(static_cast<quint8>(receiveBuffer[i]), 2, 16, QLatin1Char('0'));
        str += " ";
    }
    //将接收到的数据打印
    MainWindow::LogPrint(str);
}

//日志输出
void MainWindow::LogPrint(const QString& text)
{
    ui->textEdit->append(text);
}

在绑定按钮的点击槽函数实现socket的初始化和线程处理

//绑定按钮点击
void MainWindow::on_pushButton_2_clicked()
{
    QString srcip = ui->lineEdit->text();
    quint16 srcRcvPort = ui->lineEdit_4->text().toInt();
    quint16 srcSedPort = ui->lineEdit_3->text().toInt();

    QString dstip = ui->lineEdit_2->text();
    quint16 dstRcvPort = ui->lineEdit_6->text().toInt();
    quint16 dstSedPort = ui->lineEdit_5->text().toInt();

    //绑定接收端口
    receiveClass->ReceiveSocketInif(srcip,srcRcvPort);

    //将uDPReceiver移动到udpReceiveThread线程中执行
    receiveClass->moveToThread(udpReceiveThread);

    //连接线程线程开始信号到UDP接收
    connect(udpReceiveThread, &QThread::started, receiveClass, &ReceiveClass::startReceiving);

    //收到数据后连接到数据处理槽函数
    connect(receiveClass, &ReceiveClass::datagramReceived, this, &MainWindow::handleReceivedDatagram);

    udpReceiveThread->start();

}

然后注意在绑定测试的时候,注意在自己电脑上需要添加自己的IP,不然绑定会失败。

测试效果:

作者:zhouzhouyaonvli

物联沃分享整理
物联沃-IOTWORD物联网 » 使用多线程实现QT UDP接收

发表评论