QDataStream 解析网络,或串口传来的数据
推荐通用模式(支持复杂类型)
1. 定义结构体 + 序列化操作符
struct ArrayData {
quint32 timestamp;
QString sensorName; // 包含非POD类型
qreal values[3];
friend QDataStream &operator<<(QDataStream &out, const ArrayData &d) {
out << d.timestamp
<< d.sensorName
<< d.values[0] << d.values[1] << d.values[2];
return out;
}
friend QDataStream &operator>>(QDataStream &in, ArrayData &d) {
in >> d.timestamp
>> d.sensorName
>> d.values[0] >> d.values[1] >> d.values[2];
return in;
}
};
2. 安全解析流程
QDataStream ds(data);
ds.setByteOrder(QDataStream::LittleEndian);
// 使用事务机制处理不完整数据
ds.startTransaction();
ArrayData dat_snd;
ds >> dat_snd;
if (!ds.commitTransaction()) {
qDebug() << "等待更多数据...";
return;
}
// 检查数据有效性
if (dat_snd.timestamp == 0) {
qWarning() << "无效时间戳";
return;
}
关键注意事项
-
类型安全:
- 发送端与接收端必须使用完全相同的类型(如
qint32
vsquint32
会导致错误) - 避免使用
float/double
等平台相关类型,优先使用qreal
- 发送端与接收端必须使用完全相同的类型(如
-
协议设计:
// 推荐数据包格式 struct PacketHeader { quint32 magic = 0xA0B0C0D0; // 魔数校验 quint32 dataSize; // 数据部分大小 quint16 version = 1; // 协议版本 };
-
错误处理:
switch (ds.status()) { case QDataStream::ReadPastEnd: qCritical() << "数据不足"; break; case QDataStream::ReadCorruptData: qCritical() << "数据损坏"; break; // ... 其他状态处理 }
-
性能优化:
// 预分配缓冲区 m_buffer.reserve(1024); // 批量处理数据 QVector<ArrayData> batchData; while (!ds.atEnd()) { ArrayData data; ds >> data; batchData.append(data); }
完整网络处理示例
class DataReceiver : public QObject {
Q_OBJECT
public:
explicit DataReceiver(QTcpSocket *socket) : m_socket(socket) {
connect(socket, &QTcpSocket::readyRead, this, &DataReceiver::readData);
}
private:
QTcpSocket *m_socket;
QByteArray m_buffer;
quint32 m_expectedSize = 0;
void readData() {
m_buffer.append(m_socket->readAll());
QDataStream ds(&m_buffer, QIODevice::ReadOnly);
ds.setByteOrder(QDataStream::LittleEndian);
while (true) {
if (m_expectedSize == 0) {
if (m_buffer.size() < sizeof(PacketHeader)) return;
PacketHeader header;
ds >> header;
if (header.magic != 0xA0B0C0D0) {
qCritical() << "协议头校验失败";
m_socket->disconnectFromHost();
return;
}
m_expectedSize = header.dataSize;
}
if (m_buffer.size() < m_expectedSize) return;
QByteArray packetData = m_buffer.left(m_expectedSize);
m_buffer.remove(0, m_expectedSize);
m_expectedSize = 0;
processPacket(packetData);
}
}
void processPacket(const QByteArray &data) {
QDataStream ds(data);
ds.setByteOrder(QDataStream::LittleEndian);
ArrayData dat_snd;
ds >> dat_snd;
if (ds.status() == QDataStream::Ok) {
emit newDataReceived(dat_snd);
} else {
qWarning() << "无效数据包";
}
}
signals:
void newDataReceived(const ArrayData &data);
};
建议通过以下方式确保可靠性:
- 添加 CRC 校验字段
- 使用协议版本控制
- 实现超时重传机制
- 记录数据流日志用于调试