Skip to content

简单封包拆包协议

1 需求

平时通讯经常用到遵循一定协议封包和拆包。分享一个简单的解决方案。

2 项目

https://github.com/BeyondXinXin/study_qt

3 代码

#include <QByteArray>
#include <QDataStream>
#include <QDebug>
#include <QFile>

class ProtocalData
{
public:
    enum TcpDataType
    {
        EMPTY = 0x00,
        CMD_NAV_REALTIME_DATA = 0x01, //  navigation real time data
    };

public:
    ProtocalData()
    {
        header_ = '[';
        type_ = EMPTY;
        len_ = 0x00;
        data_.clear();
        checksum_ = 0x00;
        tail_ = ']';
    }

    void SetData(const QByteArray &data, const char &type)
    {
        this->data_ = data;
        this->type_ = type;
    }

    QByteArray MakeSendData()
    {
        QByteArray send_array;
        len_ = data_.size();
        send_array.append(static_cast<char *>(&header_), sizeof(header_));
        send_array.append(static_cast<char *>(&type_), sizeof(type_));
        send_array.append((char *)(&len_), sizeof(len_));
        send_array.append(data_);
        checksum_ = qChecksum(send_array.data(), static_cast<quint32>(send_array.size()));
        send_array.append((char *)(&checksum_), sizeof(checksum_));
        send_array.append(static_cast<char *>(&tail_), sizeof(tail_));
        return send_array;
    }

    bool AnalysisData(QByteArray &receice_array)
    {
        QDataStream stream(&receice_array, QIODevice::ReadOnly);
        stream.setByteOrder(QDataStream::LittleEndian);
        stream.readRawData(&header_, sizeof(header_));
        stream.readRawData(&type_, sizeof(type_));
        stream >> len_;
        stream.skipRawData(len_);
        data_ = receice_array.mid(sizeof(header_) + sizeof(type_) + sizeof(len_), len_);
        stream >> checksum_;
        stream.readRawData(&tail_, sizeof(tail_));
        QByteArray check_arr = receice_array.left(
          static_cast<int>(sizeof(header_) + sizeof(type_) + sizeof(len_)) + len_);
        quint16 checksum = qChecksum(check_arr.data(), static_cast<quint32>(check_arr.size()));
        if (checksum != checksum_) {
            return false;
        }
        return true;
    }

    QByteArray GetData() const
    {
        return data_;
    }

private:
    char header_;
    char type_;
    qint32 len_;
    QByteArray data_;
    quint16 checksum_;
    char tail_;
};

QString ByteArrayToHexStr(const QByteArray &data)
{
    QString temp = "";
    QString hex = data.toHex();
    for (int i = 0; i < hex.length(); i = i + 2) {
        temp += hex.mid(i, 2) + " ";
    }
    return temp.trimmed().toUpper();
}

int main()
{
    QByteArray array;
    QDataStream stream(&array, QIODevice::Append);
    stream.setByteOrder(QDataStream::LittleEndian);
    stream << 10.0 << 10.0 << 10.0
           << 10.0 << 10.0 << 10.0;

    ProtocalData protocal_data;
    protocal_data.SetData(array, char(ProtocalData::CMD_NAV_REALTIME_DATA));
    array = protocal_data.MakeSendData();

    QString str;
    str = ByteArrayToHexStr(array);
    qDebug() << str;

    if (protocal_data.AnalysisData(array)) {
        str = ByteArrayToHexStr(protocal_data.GetData());
        qDebug() << str;
    }

    QFile file("file.txt");
    file.open(QIODevice::WriteOnly);
    QTextStream out(&file);
    out << str;

    return 0;
}