自学内容网 自学内容网

Qt 实现网络数据报文大小端数据的收发

1.大小端数据简介

大小端(Endianness)是计算机体系结构的一个术语,它描述了多字节数据在内存中的存储顺序。以下是大小端的定义和它们的特点:

大端(Big-Endian)
在大端模式中,一个字的最高有效字节(MSB,即最左边的那位)存储在最低的内存地址处,而最低有效字节(LSB,即最右边的那位)存储在最高的内存地址处。

例如,假设有一个16位的数字 0x1234,其在内存中的存储顺序如下:

地址增加方向 -->

[ 12 ] [ 34 ]

其中 [12] 是高字节,存储在低地址处;[34] 是低字节,存储在高地址处。

小端(Little-Endian)
在小端模式中,情况正好相反:一个字的最低有效字节存储在最低的内存地址处,而最高有效字节存储在最高的内存地址处。

继续上面的例子,16位的数字 0x1234 在小端模式下的存储顺序如下:

地址增加方向 -->

[ 34 ] [ 12 ]

其中 [34] 是低字节,存储在低地址处;[12] 是高字节,存储在高地址处。

2.小端数据收发

假设我们现在有一个UDP头的数据结构如下所示。

    //UDP协议头
    typedef struct
    {
        quint16 type;               //报文类型
        quint16 num;                //报文序号,取值范围为0~65535
        quint32 len;                //报文长度
        quint16 srcAddr;            //信源地址
        quint16 dstAddr;            //信宿地址
        quint8  year;               //发送时间  年份后两位   UTC时间
        quint8  month;
        quint8  day;
        quint8  hour;
        quint8  minute;
        quint8  second;
    }UdpHeader;

数据发送:组包。

QByteArray pack(const Protocol::UdpHeader &header)
{
    QByteArray byte;
    byte.append((char*)&(header.type),2);
    byte.append((char*)&(header.num),2);
    byte.append((char*)&(header.len),4);
    byte.append((char*)&(header.srcAddr),2);
    byte.append((char*)&(header.dstAddr),2);

    QString format = "yy-MM-dd-hh-mm-ss";
    QDateTime dateTime = QDateTime::currentDateTime();
    dateTime.setTimeSpec(Qt::LocalTime);

    QDateTime utcTime = dateTime.toUTC();

    QString strUtcTime = utcTime.toString(format);

    QStringList timeList = strUtcTime.split('-');

    quint8 year = timeList.at(0).toInt();
    quint8 month = timeList.at(1).toInt();
    quint8 day = timeList.at(2).toInt();
    quint8 hour = timeList.at(3).toInt();
    quint8 minute = timeList.at(4).toInt();
    quint8 sec = timeList.at(5).toInt();

    byte.append(year);
    byte.append(month);
    byte.append(day);
    byte.append(hour);
    byte.append(minute);
    byte.append(sec);

    return byte;
}

数据接收:拆包

void unPack(const QByteArray &byte, Protocol::UdpHeader &header)
{
    if(byte.size() != UDP_HEADER_LEN)
    {
        return;
    }

    memcpy(&header,byte.data(),sizeof(Protocol::UdpHeader));
}

3.大端数据收发

还是上面的头例子。
数据发送:组包。
使用QDataStream类作为辅助,设置setByteOrder为大端序列。

QByteArray packBigEndian(const Protocol::UdpHeader &header)
{
    QByteArray byte;
    QDataStream stream(&byte,QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::BigEndian);

    stream<<(header.type);
    stream<<(header.num);
    stream<<(header.len);
    stream<<(header.srcAddr);
    stream<<(header.dstAddr);

    QString format = "yy-MM-dd-hh-mm-ss";
    QDateTime dateTime = QDateTime::currentDateTime();
    dateTime.setTimeSpec(Qt::LocalTime);

    QDateTime utcTime = dateTime.toUTC();

    QString strUtcTime = utcTime.toString(format);

    QStringList timeList = strUtcTime.split('-');

    quint8 year = timeList.at(0).toInt();
    quint8 month = timeList.at(1).toInt();
    quint8 day = timeList.at(2).toInt();
    quint8 hour = timeList.at(3).toInt();
    quint8 minute = timeList.at(4).toInt();
    quint8 sec = timeList.at(5).toInt();

    stream<<year;
    stream<<month;
    stream<<day;
    stream<<hour;
    stream<<minute;
    stream<<sec;

    return byte;
}

数据接收:拆包。
对于多字节的数据,都需要单独使用qToBigEndian转换为大端。

void unPackBigEndian(const QByteArray &byte, Protocol::UdpHeader &header)
{
    if(byte.size() != UDP_HEADER_LEN)
    {
        return;
    }

    memcpy(&header,byte.data(),sizeof(Protocol::UdpHeader));
    header.type = qToBigEndian(header.type);
    header.num= qToBigEndian(header.num);
    header.len= qToBigEndian(header.len);
    header.srcAddr= qToBigEndian(header.srcAddr);
    header.dstAddr= qToBigEndian(header.dstAddr);
}

原文地址:https://blog.csdn.net/wzz953200463/article/details/143976207

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!