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

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;
}

关键注意事项

  1. 类型安全

    • 发送端与接收端必须使用完全相同的类型(如 qint32 vs quint32 会导致错误)
    • 避免使用 float/double 等平台相关类型,优先使用 qreal
  2. 协议设计

    // 推荐数据包格式
    struct PacketHeader {
        quint32 magic = 0xA0B0C0D0;  // 魔数校验
        quint32 dataSize;            // 数据部分大小
        quint16 version = 1;         // 协议版本
    };
    
  3. 错误处理

    switch (ds.status()) {
        case QDataStream::ReadPastEnd:
            qCritical() << "数据不足";
            break;
        case QDataStream::ReadCorruptData:
            qCritical() << "数据损坏";
            break;
        // ... 其他状态处理
    }
    
  4. 性能优化

    // 预分配缓冲区
    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);
};

建议通过以下方式确保可靠性:

  1. 添加 CRC 校验字段
  2. 使用协议版本控制
  3. 实现超时重传机制
  4. 记录数据流日志用于调试

相关文章:

  • 计算机组成原理-存储器
  • c/c++ 使用libgeotiff读取全球高程数据ETOPO
  • Prompt工程提示词(1-6章)
  • Python中NumPy的统计运算
  • 控制单元设计(Control Unit, CU)
  • 【C++初学】课后作业汇总复习(七) 指针-深浅copy
  • 批量将文件名称、文件路径、文件扩展名提取到 Excel 清单
  • QMT美林时钟策略(15年11倍,年化13.5%策略)
  • 【C++算法】57.哈希表_判断是否互为字符重排
  • AF3 Cropper类解读
  • 音视频转换器 AV 接口静电保护方案
  • 状态压缩dp
  • Odrive源码分析(六) 相关控制变量传递
  • 基于redis 实现我的收藏功能优化详细设计方案
  • HCIP第十一天
  • 攻防世界——Web题ez_curl
  • 代码学习总结(二)
  • AIDD-人工智能药物-pyecharts-gallery
  • 滑动窗口(4)—将x减到0的最⼩操作数
  • 基于时间序列分解与XGBoost的交通通行时间预测方法解析
  • 网站上如何做相关推荐/网络推广需要什么
  • 淄博 网站制作/免费发seo外链平台
  • 惠州网站建设米普可思/黄石市seo关键词优化怎么做