【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();
}
代码说明
-
ClassA:
- 实现TCP服务器功能(端口监听、客户端连接管理)
- 使用
m_buffer
处理TCP粘包/分包问题 - 当收到完整数据包时发射
dataReceived
信号
-
ClassB:
- 通过槽函数
parseData
接收数据 - 示例解析逻辑展示数据基本信息(长度、十六进制和文本内容)
- 通过槽函数
-
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!"
=======================
关键点解释
-
粘包处理:
- 使用
m_buffer
累积数据 - 通过4字节长度头判断数据完整性
- 使用
mid()
和remove()
处理缓冲区
- 使用
-
字节序处理:
- 使用
qFromBigEndian
读取网络字节序 - 通过
QDataStream
设置字节序
- 使用
-
线程安全:
- 如果ClassA/ClassB在多个线程工作,需添加:
connect(&receiver, &ClassA::dataReceived, &parser, &ClassB::parseData, Qt::QueuedConnection);
- 如果ClassA/ClassB在多个线程工作,需添加:
-
扩展建议:
- 在ClassB中添加具体业务协议解析逻辑
- 在ClassA中添加错误处理(
errorOccurred
信号) - 使用QSharedPointer管理类实例生命周期