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

【QT】类A接收TCP数据并通过信号通知类B解析

以下是基于Qt的完整示例代码,包含类A接收TCP数据并通过信号通知类B解析的实现:

------------------ ClassA.h 网络数据接收类 ------------------
#pragma once#include <QTcpServer>
#include <QTcpSocket>
#include <QObject>class ClassA : public QObject
{Q_OBJECT
public:explicit ClassA(QObject *parent = nullptr);void startServer(quint16 port);  // 启动TCP服务器signals:void dataReceived(const QByteArray &data);  // 数据接收信号private slots:void onNewConnection();void onReadyRead();void onDisconnected();private:QTcpServer *m_server;QTcpSocket *m_socket;QByteArray m_buffer;  // 用于处理粘包/分包
};
------------------ ClassA.cpp ------------------
#include "ClassA.h"
#include <QDebug>ClassA::ClassA(QObject *parent) : QObject(parent)
{m_server = new QTcpServer(this);connect(m_server, &QTcpServer::newConnection, this, &ClassA::onNewConnection);
}void ClassA::startServer(quint16 port)
{if (!m_server->listen(QHostAddress::Any, port)) {qWarning() << "Server start failed:" << m_server->errorString();} else {qInfo() << "Server listening on port" << port;}
}void ClassA::onNewConnection()
{m_socket = m_server->nextPendingConnection();connect(m_socket, &QTcpSocket::readyRead, this, &ClassA::onReadyRead);connect(m_socket, &QTcpSocket::disconnected, this, &ClassA::onDisconnected);qInfo() << "New client connected";
}void ClassA::onReadyRead()
{m_buffer += m_socket->readAll();// 示例拆包逻辑:假设协议头4字节表示数据长度(网络字节序)while (m_buffer.size() >= 4) {// 读取数据长度(假设大端序)quint32 packetLength = qFromBigEndian<quint32>(reinterpret_cast<const uchar*>(m_buffer.constData()));// 检查数据是否完整if (m_buffer.size() < static_cast<int>(packetLength + 4)) {break;  // 数据不完整,等待下次接收}// 提取完整数据包QByteArray packet = m_buffer.mid(4, packetLength);emit dataReceived(packet);  // 发射信号// 移除已处理数据m_buffer.remove(0, 4 + packetLength);}
}void ClassA::onDisconnected()
{qInfo() << "Client disconnected";m_socket->deleteLater();
}
------------------ ClassB.h 数据解析类 ------------------
#pragma once#include <QObject>class ClassB : public QObject
{Q_OBJECT
public:explicit ClassB(QObject *parent = nullptr);public slots:void parseData(const QByteArray &data);  // 数据解析槽函数
};
------------------ ClassB.cpp ------------------
#include "ClassB.h"
#include <QDebug>ClassB::ClassB(QObject *parent) : QObject(parent) {}void ClassB::parseData(const QByteArray &data)
{// 示例解析逻辑qDebug() << "\n=== Received Packet ===";qDebug() << "Length:" << data.length();qDebug() << "Hex Content:" << data.toHex();qDebug() << "Text Content:" << data;qDebug() << "=======================";
}
------------------ main.cpp 测试程序 ------------------
#include <QCoreApplication>
#include "ClassA.h"
#include "ClassB.h"int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 创建对象ClassA receiver;ClassB parser;// 连接信号槽QObject::connect(&receiver, &ClassA::dataReceived, &parser, &ClassB::parseData);// 启动服务器receiver.startServer(12345);// 模拟客户端发送数据(实际应用中应为独立客户端)QTcpSocket client;client.connectToHost(QHostAddress::LocalHost, 12345);if(client.waitForConnected()) {// 构造测试数据包(4字节长度头 + 实际数据)QByteArray packet1 = "Hello";QByteArray packet2 = "Qt Signal/Slot!";// 添加长度头(大端序)QByteArray data;QDataStream stream(&data, QIODevice::WriteOnly);stream.setByteOrder(QDataStream::BigEndian);// 数据包1stream << static_cast<quint32>(packet1.size());data.append(packet1);// 数据包2stream << static_cast<quint32>(packet2.size());data.append(packet2);client.write(data);client.waitForBytesWritten();}return a.exec();
}

代码说明

  1. ClassA

    • 实现TCP服务器功能(端口监听、客户端连接管理)
    • 使用m_buffer处理TCP粘包/分包问题
    • 当收到完整数据包时发射dataReceived信号
  2. ClassB

    • 通过槽函数parseData接收数据
    • 示例解析逻辑展示数据基本信息(长度、十六进制和文本内容)
  3. main.cpp

    • 创建ClassA和ClassB实例
    • 连接信号与槽
    • 模拟客户端发送包含两个数据包的测试数据

运行效果

Server listening on port 12345
New client connected=== Received Packet ===
Length: 5
Hex Content: "48656c6c6f"
Text Content: "Hello"
========================== Received Packet ===
Length: 14
Hex Content: "5174205369676e616c2f536c6f7421"
Text Content: "Qt Signal/Slot!"
=======================

关键点解释

  1. 粘包处理

    • 使用m_buffer累积数据
    • 通过4字节长度头判断数据完整性
    • 使用mid()remove()处理缓冲区
  2. 字节序处理

    • 使用qFromBigEndian读取网络字节序
    • 通过QDataStream设置字节序
  3. 线程安全

    • 如果ClassA/ClassB在多个线程工作,需添加:
      connect(&receiver, &ClassA::dataReceived, &parser, &ClassB::parseData, Qt::QueuedConnection);
      
  4. 扩展建议

    • 在ClassB中添加具体业务协议解析逻辑
    • 在ClassA中添加错误处理(errorOccurred信号)
    • 使用QSharedPointer管理类实例生命周期

相关文章:

  • 运行在华为云kubernetes应用接入APM服务
  • [Java实战] Docker 快速启动 Sentinel 控制台(二十八)
  • 园区无人机智能巡检项目方案
  • PDF处理控件Aspose.PDF教程:以编程方式将 PDF 导出为 JPG
  • React中使用ahooks处理业务场景
  • 使用 React PDF 构建 React.js PDF 查看器的指南
  • [特殊字符] React Fiber架构与Vue设计哲学撕逼实录
  • React+TypeScript多步骤表单:告别表单地狱的现代解决方案
  • cplex12.9 安装教程以及下载
  • 33、魔法防御术——React 19 安全攻防实战
  • React的合成事件(SyntheticEventt)
  • React TS中如何化简DOM事件的定义
  • React 第四十四节Router中 usefetcher的使用详解及注意事项
  • 基于“岗课赛证”融通的农业物联网专业教学方案
  • WHAT - CSS 中的 min-height
  • 区间内最远互质点对
  • PostgreSQL初体验
  • ubuntu设置conda虚拟环境
  • 【TCGA-CRC】TCGA数据读取
  • 基于springboot的在线教育系统【附源码】
  • 锚定建设“中国樱桃第一县”目标,第六届澄城樱桃营销季启动
  • 凤阳县鼓楼四周连夜搭起围挡,安徽省文物局已介入调查
  • 出生于1991年,石秀清拟提名为铜陵市辖县(区)政府副县(区)长人选
  • 金融监管总局将研究出台专门的城市更新项目贷款管理办法:引导大力支持城中村的改造等
  • 多家国有大行存款利率即将迎来新一轮下调
  • 世卫大会连续九年拒绝涉台提案