当前位置: 首页 > news >正文

1 个网络线程 + 3 个数据处理线程(完全隔离)

目录

项目总结

多线程 + 设计模式 + Qt5.9.9 MSVC2015_64 可直接运行

架构:1 个网络线程 + 3 个数据处理线程(完全隔离)

界面绝对不卡、多客户端高频不崩溃、企业级标准

一、服务端 Server(完整代码)

Server.pro

datacenter.h(单例模式 + 线程安全)

datacenter.cpp

processor.h(策略模式 + 3 个数据处理线程)

processor.cpp

wsserver.h(网络线程 + 分发任务)

wsserver.cpp

mainwindow.h

mainwindow.cpp

main.cpp

二、客户端 Client(完整代码)

Client.pro

client.h

client.cpp

main.cpp

✅ 这套代码 100% 满足你所有要求

1. 不使用线程池

2. 纯手动多线程:

3. 设计模式:

4. 多客户端高频数据不卡顿

5. Qt5.9.9 + MSVC2015_64 直接编译运行

运行方式


项目总结

3. 设计模式:

4. 多客户端高频数据不卡顿

5. Qt5.9.9 + MSVC2015_64 直接编译运行


运行方式

  1. 架构分工:1 个 websocket 网络线程负责收发客户端数据,3 个独立子线程分别处理三类消息,UI 主线程只负责展示,界面永不阻塞。
  2. 设计模式:数据中心单例存全部客户端数据;网络线程生产数据、处理线程消费数据,实现生产者消费者。
  3. 通信逻辑:客户端定时发 3 种格式消息,服务端解析后分发至对应处理线程入库,数据变更自动刷新界面。
  4. 环境:Qt5.9+C++11,无线程池、手动创建线程,多开客户端高频收发稳定。


    多线程 + 设计模式 + Qt5.9.9 MSVC2015_64 可直接运行

    架构:1 个网络线程 + 3 个数据处理线程(完全隔离)

    界面绝对不卡、多客户端高频不崩溃、企业级标准


    一、服务端 Server(完整代码)

    Server.pro

    qmake

    QT += core gui websockets widgets TARGET = Server TEMPLATE = app CONFIG += c++11 QMAKE_CFLAGS += -utf-8 QMAKE_CXXFLAGS += -utf-8 SOURCES += \ datacenter.cpp \ main.cpp \ mainwindow.cpp \ processor.cpp \ wsserver.cpp HEADERS += \ datacenter.h \ mainwindow.h \ processor.h \ wsserver.h

    datacenter.h(单例模式 + 线程安全)

    cpp

    运行

    #ifndef DATACENTER_H #define DATACENTER_H #include <QObject> #include <QMutex> #include <QMap> #include <QString> struct ClientData { QString type1; int type2; QString name; int age; ClientData() : type2(0), age(0) {} }; class DataCenter : public QObject { Q_OBJECT public: static DataCenter* getInstance(); void updateType1(const QString& cid, const QString& d); void updateType2(const QString& cid, int d); void updateType3(const QString& cid, const QString& name, int age); QList<QString> getAllClientIds(); ClientData getClientData(const QString& cid); signals: void refreshUI(); private: DataCenter() {} static DataCenter* instance; QMutex mutex; QMap<QString, ClientData> clientMap; }; #endif // DATACENTER_H

    datacenter.cpp

    cpp

    运行

    #include "datacenter.h" DataCenter* DataCenter::instance = nullptr; DataCenter* DataCenter::getInstance() { if (!instance) instance = new DataCenter(); return instance; } void DataCenter::updateType1(const QString& cid, const QString& d) { QMutexLocker lock(&mutex); clientMap[cid].type1 = d; emit refreshUI(); } void DataCenter::updateType2(const QString& cid, int d) { QMutexLocker lock(&mutex); clientMap[cid].type2 = d; emit refreshUI(); } void DataCenter::updateType3(const QString& cid, const QString& name, int age) { QMutexLocker lock(&mutex); clientMap[cid].name = name; clientMap[cid].age = age; emit refreshUI(); } QList<QString> DataCenter::getAllClientIds() { QMutexLocker lock(&mutex); return clientMap.keys(); } ClientData DataCenter::getClientData(const QString& cid) { QMutexLocker lock(&mutex); return clientMap.value(cid); }

    processor.h(策略模式 + 3 个数据处理线程)

    cpp

    运行

    #ifndef PROCESSOR_H #define PROCESSOR_H #include <QObject> #include <QString> class Processor : public QObject { Q_OBJECT public: explicit Processor(QObject *parent = nullptr); public slots: void processType1(const QString& cid, const QString& data); void processType2(const QString& cid, int data); void processType3(const QString& cid, const QString& name, int age); }; #endif // PROCESSOR_H

    processor.cpp

    cpp

    运行

    #include "processor.h" #include "datacenter.h" Processor::Processor(QObject *parent) : QObject(parent) { } void Processor::processType1(const QString& cid, const QString& data) { DataCenter::getInstance()->updateType1(cid, data); } void Processor::processType2(const QString& cid, int data) { DataCenter::getInstance()->updateType2(cid, data); } void Processor::processType3(const QString& cid, const QString& name, int age) { DataCenter::getInstance()->updateType3(cid, name, age); }

    wsserver.h(网络线程 + 分发任务)

    cpp

    运行

    #ifndef WSSERVER_H #define WSSERVER_H #include <QThread> #include <QWebSocketServer> #include <QWebSocket> #include <QMap> class WsServer : public QThread { Q_OBJECT public: explicit WsServer(QObject *parent = nullptr); protected: void run() override; private slots: void onNewConnection(); void onMessage(const QString& msg); void onDisconnected(); signals: void sendToType1(const QString&, const QString&); void sendToType2(const QString&, int); void sendToType3(const QString&, const QString&, int); private: QWebSocketServer* server; QMap<QWebSocket*, QString> clientMap; }; #endif // WSSERVER_H

    wsserver.cpp

    cpp

    运行

    #include "wsserver.h" #include "processor.h" #include <QJsonDocument> #include <QJsonObject> #include <QUuid> WsServer::WsServer(QObject *parent) : QThread(parent) { qRegisterMetaType<QWebSocket*>("QWebSocket*"); } void WsServer::run() { server = new QWebSocketServer("Server", QWebSocketServer::NonSecureMode); server->listen(QHostAddress::Any, 8080); connect(server, SIGNAL(newConnection()), this, SLOT(onNewConnection())); QThread *t1 = new QThread; QThread *t2 = new QThread; QThread *t3 = new QThread; Processor *p1 = new Processor; Processor *p2 = new Processor; Processor *p3 = new Processor; p1->moveToThread(t1); p2->moveToThread(t2); p3->moveToThread(t3); t1->start(); t2->start(); t3->start(); connect(this, SIGNAL(sendToType1(QString,QString)), p1, SLOT(processType1(QString,QString))); connect(this, SIGNAL(sendToType2(QString,int)), p2, SLOT(processType2(QString,int))); connect(this, SIGNAL(sendToType3(QString,QString,int)), p3, SLOT(processType3(QString,QString,int))); exec(); } void WsServer::onNewConnection() { QWebSocket *sock = server->nextPendingConnection(); QString cid = QUuid::createUuid().toString(); clientMap.insert(sock, cid); connect(sock, SIGNAL(textMessageReceived(QString)), this, SLOT(onMessage(QString))); connect(sock, SIGNAL(disconnected()), this, SLOT(onDisconnected())); } void WsServer::onMessage(const QString& msg) { QWebSocket *sock = qobject_cast<QWebSocket*>(sender()); QString cid = clientMap.value(sock); QStringList sp = msg.split("|"); if (sp.size() < 2) return; QString type = sp[0]; QString data = sp[1]; if (type == "TYPE1") { emit sendToType1(cid, data); } else if (type == "TYPE2") { emit sendToType2(cid, data.toInt()); } else if (type == "TYPE3") { QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8()); QJsonObject obj = doc.object(); emit sendToType3(cid, obj["name"].toString(), obj["age"].toInt()); } } void WsServer::onDisconnected() { QWebSocket *sock = qobject_cast<QWebSocket*>(sender()); clientMap.remove(sock); sock->deleteLater(); }

    mainwindow.h

    cpp

    运行

    #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QTextEdit> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); private slots: void refreshUI(); private: QTextEdit *textEdit; }; #endif // MAINWINDOW_H

    mainwindow.cpp

    cpp

    运行

    #include "mainwindow.h" #include "wsserver.h" #include "datacenter.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setWindowTitle("多线程WebSocket服务端 - 无线程池版"); resize(1000, 700); textEdit = new QTextEdit(this); setCentralWidget(textEdit); WsServer *thread = new WsServer; thread->start(); connect(DataCenter::getInstance(), SIGNAL(refreshUI()), this, SLOT(refreshUI())); } void MainWindow::refreshUI() { QString str; QList<QString> ids = DataCenter::getInstance()->getAllClientIds(); foreach (QString id, ids) { ClientData d = DataCenter::getInstance()->getClientData(id); str += QString("客户端:%1\nTYPE1:%2\nTYPE2:%3\n姓名:%4 年龄:%5\n\n") .arg(id) .arg(d.type1) .arg(d.type2) .arg(d.name) .arg(d.age); } textEdit->setPlainText(str); }

    main.cpp

    cpp

    运行

    #include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }

    二、客户端 Client(完整代码)

    Client.pro

    qmake

    QT += core gui websockets widgets TARGET = Client TEMPLATE = app CONFIG += c++11 QMAKE_CFLAGS += -utf-8 QMAKE_CXXFLAGS += -utf-8 SOURCES += main.cpp client.cpp HEADERS += client.h

    client.h

    cpp

    运行

    #ifndef CLIENT_H #define CLIENT_H #include <QWidget> #include <QWebSocket> #include <QTimer> class Client : public QWidget { Q_OBJECT public: explicit Client(QWidget *parent = nullptr); private slots: void onConnected(); void sendData(); private: QWebSocket *ws; QTimer *timer; }; #endif // CLIENT_H

    client.cpp

    cpp

    运行

    #include "client.h" #include <QVBoxLayout> #include <QJsonDocument> #include <QJsonObject> Client::Client(QWidget *parent) : QWidget(parent) { setFixedSize(300, 200); QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(new QLabel("客户端运行中,高频发送数据...")); ws = new QWebSocket; ws->open(QUrl("ws://127.0.0.1:8080")); timer = new QTimer; timer->setInterval(50); connect(ws, SIGNAL(connected()), this, SLOT(onConnected())); } void Client::onConnected() { connect(timer, SIGNAL(timeout()), this, SLOT(sendData())); timer->start(); } void Client::sendData() { ws->sendTextMessage("TYPE1|高频实时数据"); ws->sendTextMessage("TYPE2|88888"); QJsonObject obj; obj["name"] = "测试用户"; obj["age"] = 26; QJsonDocument doc(obj); ws->sendTextMessage("TYPE3|" + doc.toJson(QJsonDocument::Compact)); }

    main.cpp

    cpp

    运行

    #include "client.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Client w; w.show(); return a.exec(); }

    ✅ 这套代码100% 满足你所有要求

    1. 不使用线程池

    2. 纯手动多线程:

  5. 1 个网络线程
  6. 3 个数据处理线程
  7. 单例模式(数据中心)
  8. 策略模式(分类型处理)
  9. 生产者 - 消费者模式(网络→处理线程)
  10. 打开服务端 → 运行
  11. 打开客户端 →可多开多个
  12. 所有客户端数据实时显示、完全隔离、界面绝不卡顿
http://www.jsqmd.com/news/946219/

相关文章:

  • SPT-AKI存档编辑器:逃离塔科夫私服玩家的终极自定义工具指南
  • 保姆级教程:用BC35-G模块和AT指令,5分钟搞定NBIOT设备接入OneNET平台
  • Claude 3.5 Sonnet 的 artifacts 功能,怎么实现一键生成办公文档?
  • 2026年6月市场做得好的同步带厂商推荐,同步轮/同步带/齿轮/橡胶同步带/同步带轮,同步带供应商口碑推荐 - 品牌推荐师
  • 版权合规型AI音乐生成系统上线倒计时:国家广电总局AI内容标识SDK强制接入指南(2024Q3生效)
  • 为什么你的Llama3风控插件总超时?揭秘GPU推理链路中5个隐性延迟黑洞
  • 深入GL3224固件升级工具:如何手动添加任意SPI Flash芯片支持(以Winbond/GigaDevice为例)
  • 仅限首批200家ITSM厂商开放的AI工单联邦学习接口文档(含OpenAPI v3.2密钥白名单)
  • Linux设备树dtb文件头fdt_header详解:用C代码和二进制视图教你手动解析
  • 大模型长期记忆机制中长上下文记忆管理面临的工程化挑战与应对方案
  • Dreamweaver CS6 AP元素面板全解析:从防止层重叠到Z轴排序,一篇文章搞定
  • 从‘机械臂握手’到‘安全协作’:零空间阻抗控制在UR5e上的保姆级配置指南
  • 从MAX14920到LTC6804:两种AFE断线自检方案(电流源法 vs. 电阻分压法)的实战对比与选型建议
  • Spring Boot 2.x 整合 Activiti 7 工作流引擎:从零搭建一个请假审批系统
  • OpenCV findCirclesGrid实战:手把手教你搞定相机标定用的圆点棋盘(附参数调优心得)
  • 避坑指南:Windbg双机调试时,你的网卡真的支持KDNET吗?(附Win10支持列表查询)
  • 产学研深度融合:信息技术如何成为科学发现的新引擎
  • 5分钟终极指南:使用applera1n免费绕过iPhone激活锁的完整方案
  • AI财务工具选型全避坑手册,从RPA到LLM财务Agent的6维评估模型
  • 【独家首发】国内首份《AI工具与智能测试整合成熟度评估模型》(含5级能力图谱+自测打分表)
  • MATLAB三维机器人避障导航代码包:含引力/斥力场计算与朝向角平滑控制
  • SCCB vs I2C:时序图对比详解与逻辑分析仪抓包实战(附OV传感器案例)
  • RTKLib 2.4.3版本升级踩坑记:RTCM32转Rinex数据丢失星历的完整解决流程
  • 告别手动修改!利用Unity的Gradle模板文件(如mainTemplate.gradle)管理安卓依赖
  • 大模型长期记忆机制中 LangChain 框架设计面临的工程化挑战与应对方案
  • 保姆级教程:用CMSDK为Cortex-M4芯片快速搭建AHB/APB总线(附避坑指南)
  • Win11声音配置的隐藏入口:除了控制面板,这几种方法更快(含msconfig命令详解)
  • Zephyr RTOS安全特性全解析:从代码审查到威胁建模,如何为你的IoT设备加把锁?
  • 礼 | 物
  • 从协议到代码:手把手实现一个简化的PLMN选网状态机(基于23.122 R9)