概括
使用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();
}