【提供完整代码】QTcpServer 多线程处理客户端发送json格式的消息的程序

概括

使用QTcpServer开发一个能多线程处理客户端发送json格式的消息的程序。

相关函数和变量如下

qtplctcpserver.h

#ifndef QTPLCTCPSERVER_H
#define QTPLCTCPSERVER_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QThread>
#include <QJsonObject>
#include <QQueue>
#include <QMutex>
#include <QWaitCondition>
#include <QJsonDocument>
#include <QMessageBox>

//处理数据线程类
class DataProcessThread : public QThread
{
    Q_OBJECT
public:
    explicit DataProcessThread(QObject *parent = nullptr);
    ~DataProcessThread();
    void addData(const QJsonObject &data);//增加数据入队列
    void stopThread();//停止线程

signals:
    void processedData(const QJsonObject &data);

protected:
    void run() override;

private:
    QQueue<QJsonObject> m_dataQueue;//json数据队列
    QMutex m_mutex;//互斥锁
    QWaitCondition m_condition;
    bool m_isRunning;

    void processData(const QJsonObject &data);//在线程里处理数据
};


//tcp服务类
class TCPServerPlc : public QTcpServer
{
    Q_OBJECT

public:
    explicit TCPServerPlc(QObject *parent = nullptr);
    ~TCPServerPlc();
    bool startServer(quint16 port);//开启服务
    void stopServer();//关闭服务
    void sendJsonToClient(const QString &data);//发送Json数据
    QByteArray toJsonString(const QJsonObject &jsonData, bool prettyPrint = false);//json -->string
    QQueue<QJsonObject> receivedHistoryData;//保存接收到的数据
    QJsonObject currentData;//当前的json数据

protected:
    void incomingConnection(qintptr socketDescriptor) override;//新连接

private slots:
    void handleNewData();//处理新数据
    void handleDisconnected();//断开连接
    void handleProcessedData(const QJsonObject &data);// 处理来自处理线程的数据

signals:
    void haveNewData(const QJsonObject &data);//接收到新数据触发
    void haveNewConnection(QString peerAddress,quint16 peerPort);//有客户端接入触发
    void haveDisconnected(QString peerAddress,quint16 peerPort);//断开连接触发

private:
    QList<QTcpSocket*> m_clientSockets;
    DataProcessThread *m_processThread;
    QMutex m_mutex;//互斥锁
};

#endif // QTPLCTCPSERVER_H

qtplctcpserver.cpp

#include "qtplctcpserver.h"
#include <QAbstractSocket>
#include <QDebug>
#include <QListWidgetItem>
#include <qhostinfo.h>


//处理数据线程类
DataProcessThread::DataProcessThread(QObject *parent)
    : QThread(parent)
    , m_isRunning(true)
{

}

DataProcessThread::~DataProcessThread()
{
    stopThread();
    wait();
}

//增加数据入队列
void DataProcessThread::addData(const QJsonObject &data)
{
    QMutexLocker locker(&m_mutex);
    m_dataQueue.enqueue(data);
    m_condition.wakeOne();
}

//停止线程
void DataProcessThread::stopThread()
{
    QMutexLocker locker(&m_mutex);
    m_isRunning = false;
    m_condition.wakeOne();
}

//run
void DataProcessThread::run()
{
    while (m_isRunning) {
        QJsonObject data;

        {
            QMutexLocker locker(&m_mutex);
            while (m_dataQueue.isEmpty() && m_isRunning) {
                m_condition.wait(&m_mutex);
            }

            if (!m_isRunning) {
                break;
            }

            data = m_dataQueue.dequeue();
        }
        processData(data);
    }
}

//在线程里处理数据
void DataProcessThread::processData(const QJsonObject &data)
{
    // 在这里处理从PLC接收到的数据
    //qDebug() << "在当前的线程里处理数据:" << QThread::currentThread();
    // 数据处理完成后发送信号
    emit processedData(data);
}


//tcp服务类
TCPServerPlc::TCPServerPlc(QObject *parent)
    : QTcpServer(parent)
{
    m_processThread = new DataProcessThread(this);
    //  处理数据信号与槽
    connect(m_processThread, &DataProcessThread::processedData,this, &TCPServerPlc::handleProcessedData);
    m_processThread->start();
}

TCPServerPlc::~TCPServerPlc()
{
    m_processThread->stopThread();
    for (QTcpSocket* socket : m_clientSockets) {
        socket->disconnectFromHost();
    }
    qDeleteAll(m_clientSockets);
}

//开始服务
bool TCPServerPlc::startServer(quint16 port)
{
    qDebug()<<"开始服务";
    return listen(QHostAddress::Any, port);
}

//关闭服务
void TCPServerPlc::stopServer()
{
    qDebug()<<"关闭服务";
    close();
}

//新连接
void TCPServerPlc::incomingConnection(qintptr socketDescriptor)
{
    QTcpSocket *socket = new QTcpSocket(this);
    socket->setSocketDescriptor(socketDescriptor);

    connect(socket, &QTcpSocket::readyRead, this, &TCPServerPlc::handleNewData);
    connect(socket, &QTcpSocket::disconnected, this, &TCPServerPlc::handleDisconnected);

    QMutexLocker locker(&m_mutex);
    m_clientSockets.append(socket);

    qDebug() << "New client connected from:" <<socket->peerAddress().toString() << " "<< socket->peerPort();
    emit haveNewConnection(socket->peerAddress().toString(),socket->peerPort());
}

//处理新数据
void TCPServerPlc::handleNewData()
{
    QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());
    if (!socket) return;

    QByteArray data = socket->readAll();
    QJsonDocument doc = QJsonDocument::fromJson(data);

    if (!doc.isNull() && doc.isObject()) {
        QJsonObject jsonObj = doc.object();
        // 添加源socket信息到数据中
        jsonObj["clientAddress"] = socket->peerAddress().toString();
        jsonObj["clientPort"] = socket->peerPort();

        // 将数据添加到处理线程
        m_processThread->addData(jsonObj);
    }
}

//断开连接
void TCPServerPlc::handleDisconnected()
{
    QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender());
    if (socket) {
        QMutexLocker locker(&m_mutex);

        // 从客户端列表中移除这个socket
        m_clientSockets.removeOne(socket);

        // 获取客户端的信息
        QString peerAddress = socket->peerAddress().toString();
        quint16 peerPort = socket->peerPort();

        // 输出客户端信息
        qDebug() << "Client disconnected. IP:" << peerAddress << "Port:" << peerPort;

        // 删除socket对象
        socket->deleteLater();
        emit  haveDisconnected(peerAddress,peerPort);
    }
}

// 处理来自处理线程的数据
void TCPServerPlc::handleProcessedData(const QJsonObject &data)
{
    // 处理来自处理线程的数据
    //qDebug() << "接收到的数据:" << data;
    currentData=data;
    //qDebug() << "currentData:" << currentData;
    //向队列里加入接收到的数据
    receivedHistoryData.enqueue(data);

    // for (const QJsonObject &obj : receivedHistoryData) {
    //     QJsonValue device_id= obj.value("device_id");
    //     qDebug() << "Processing object:" << device_id.toString();
    // }

    //向客户端发送响应
    QString res=R"({"code":"1"})";
    sendJsonToClient(res);
    emit haveNewData(data);
}

//向客户端发送响应
// void TCPServerPlc::sendJsonToClient(const QJsonObject &data)
// {
//     QJsonDocument doc(data);
//     QByteArray jsonData = doc.toJson();

//     QMutexLocker locker(&m_mutex);
//     for (QTcpSocket* socket : m_clientSockets) {
//         socket->write(jsonData);
//     }
// }


// 向客户端发送响应
void TCPServerPlc::sendJsonToClient(const QString &jsonDataStr)
{
    // 解析传入的字符串为 QJsonObject
    QJsonDocument doc = QJsonDocument::fromJson(jsonDataStr.toUtf8());
    if (!doc.isNull() && doc.isObject()) {
        QJsonObject data = doc.object();
        // 将 QJsonObject 转换为 JSON 字符串并发送
        QByteArray jsonData = QJsonDocument(data).toJson(QJsonDocument::Compact);

        QMutexLocker locker(&m_mutex);
        //发送全部客户端
        for (QTcpSocket* socket : m_clientSockets) {
            socket->write(jsonData);
        }
    } else {
        // 如果解析失败,可以选择抛出异常或记录错误
        qDebug() << "Invalid JSON string provided:" << jsonDataStr;
    }
}

//json转string
QByteArray TCPServerPlc::toJsonString(const QJsonObject &jsonData, bool prettyPrint)
{
    QJsonDocument jsonDoc(jsonData);
    if (prettyPrint) {
        return jsonDoc.toJson(QJsonDocument::Indented);
    } else {
        return jsonDoc.toJson();
    }
}

usedemo.h

#ifndef USEDEMO_H
#define USEDEMO_H

#include "qtplctcpserver.h"

#include <QWidget>

namespace Ui {
class UseDemo;
}

class UseDemo : public QWidget
{
    Q_OBJECT

public:
    explicit UseDemo(QWidget *parent = nullptr);
    ~UseDemo();


private slots:
    void on_btnStart_clicked();
    void btnClose();
    void handleData(const QJsonObject &data);
    void handleNewConnection(QString peerAddress,quint16 peerPort);
    void handleDisconnected(QString peerAddress,quint16 peerPort);

private:
    Ui::UseDemo *ui;
    TCPServerPlc* server;
};

#endif // USEDEMO_H

usedemo.cpp

#include "usedemo.h"
#include "ui_usedemo.h"

UseDemo::UseDemo(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::UseDemo)
{
    server = new TCPServerPlc();

    connect(server, &TCPServerPlc::haveNewData, this, &UseDemo::handleData);
    connect(server, &TCPServerPlc::haveNewConnection, this, &UseDemo::handleNewConnection);
    connect(server, &TCPServerPlc::haveDisconnected, this, &UseDemo::handleDisconnected);
    ui->setupUi(this);
}

UseDemo::~UseDemo()
{
    delete server;
    delete ui;
}

void UseDemo::on_btnStart_clicked()
{
    server->startServer(12345);
}

void UseDemo::btnClose()
{
    server->close();
}

void UseDemo::handleData(const QJsonObject &jsonData)
{
    // 使用方法参数中的 jsonData
    QString device_id = jsonData.value("device_id").toString();
    QString timestamp = jsonData.value("timestamp").toString();

    QByteArray jsonStringPretty = server->toJsonString(jsonData, true);

    ui->textEdit->insertPlainText(jsonStringPretty);
    ui->device_id_text->setPlainText(device_id);
    ui->timestamp_text->setPlainText(timestamp);

}

void UseDemo::handleNewConnection(QString peerAddress, quint16 peerPort)
{
    ui->labelStaus->setText("在线");
    qDebug() << "New client connected from:" <<peerAddress<< " "<< peerPort;
    // QMessageBox msgBox;
    // msgBox.setText("新连接设备:"+peerAddress+","+peerPort);
    // msgBox.exec();
}

void UseDemo::handleDisconnected(QString peerAddress, quint16 peerPort)
{
     ui->labelStaus->setText("离线");
     qDebug() << "have Disconnected:" <<peerAddress<< " "<< peerPort;
}

main.cpp


#include <QApplication>
#include <UseDemo.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    UseDemo u;
    u.show();
    return a.exec();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Traveler飞

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

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

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

打赏作者

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

抵扣说明:

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

余额充值