Qt中对Udp数据打包发送和接收(续)

这次用一个更加复杂的数据包举例。

心跳报文结构如下:

cpp 复制代码
struct HeartbeatPacket {
    quint16 protocolId;
    quint16 version;
    quint16 totalLength;
    quint16 reserve;
    QByteArray senderAddress;
    QByteArray receiverAddress;
    quint8 sequenceNumber;
    quint8 acknowledgementNumber;
    quint8 messageFlag;
    quint8 unitCount;
    quint8 unitNumber;
    quint8 unitId;
    QByteArray unitLength;
    QByteArray timestamp;
    QByteArray deviceId;

    QByteArray toByteArray();


};

代码如下:

cpp 复制代码
QByteArray HeartbeatPacket::toByteArray() {
    QByteArray byteArray;
    QDataStream stream(&byteArray, QIODevice::WriteOnly);

    // 注意:此处可能需要考虑字节序问题
    stream << protocolId;
    stream << version;
    stream << totalLength;
    stream << reserve;
    stream.writeRawData(senderAddress.constData(), senderAddress.size());
    stream.writeRawData(receiverAddress.constData(), receiverAddress.size());
    stream << sequenceNumber;
    stream << acknowledgementNumber;
    stream << messageFlag;
    stream << unitCount;
    stream << unitNumber;
    stream << unitId;
    stream.writeRawData(unitLength.constData(), unitLength.size());
    stream.writeRawData(timestamp.constData(), timestamp.size());
    stream.writeRawData(deviceId.constData(), deviceId.size());

    return byteArray;
}

void MainWindow::sendHeartbeat(const QHostAddress &address, quint16 port)
{
    QByteArray packetData = heartbeatPacket.toByteArray();
    udpSocket.writeDatagram(packetData, address, port);
}

void MainWindow::convertVectorToHeartbeatPacket()
{
    if (dataVector.size() < 13) {
        qDebug() << "vector size too short.";
        return;
    }

    bool reverseBytes = false;  // 默认字节序为低字节在前

    auto reverseIter = dataVector[3].find("name");
    if (reverseIter != dataVector[3].end() && reverseIter->second == "reverse") {
        auto valueIter = dataVector[3].find("value");
        if (valueIter != dataVector[3].end()) {
            QString reverseValue = valueIter->second.toLower();
            if (reverseValue == "True") {
                reverseBytes = true;
            }
        }
    }

    heartbeatPacket.protocolId = dataVector[0].at("value").toUShort();
    heartbeatPacket.version = dataVector[1].at("value").toUShort();
    heartbeatPacket.totalLength = dataVector[2].at("value").toUShort();
    heartbeatPacket.reserve = dataVector[3].at("value").toUShort();

    // 设置senderAddress和receiverAddress,需要将16进制字符串转换为QByteArray,并根据reverseBytes确定字节序
    QByteArray senderAddressHex = dataVector[4].at("value").toUtf8();
    QByteArray receiverAddressHex = dataVector[5].at("value").toUtf8();
    QByteArray senderAddressBytes;
    QByteArray receiverAddressBytes;

    if (reverseBytes) {
        // 高字节在前的字节序
        for (int i = senderAddressHex.size() - 2; i >= 0; i -= 2) {
            senderAddressBytes.append(senderAddressHex.mid(i, 2).toInt(nullptr, 16));
            receiverAddressBytes.append(receiverAddressHex.mid(i, 2).toInt(nullptr, 16));
        }
    } else {
        // 低字节在前的字节序
        for (int i = 0; i < senderAddressHex.size(); i += 2) {
            senderAddressBytes.append(senderAddressHex.mid(i, 2).toInt(nullptr, 16));
            receiverAddressBytes.append(receiverAddressHex.mid(i, 2).toInt(nullptr, 16));
        }
    }

    heartbeatPacket.senderAddress = senderAddressBytes;
    heartbeatPacket.receiverAddress = receiverAddressBytes;

    heartbeatPacket.sequenceNumber = dataVector[6].at("value").toShort();
    heartbeatPacket.acknowledgementNumber = dataVector[7].at("value").toShort();
    heartbeatPacket.messageFlag = dataVector[8].at("value").toShort();
    heartbeatPacket.unitCount = dataVector[9].at("value").toShort();
    heartbeatPacket.unitNumber = dataVector[10].at("value").toShort();
    heartbeatPacket.unitId = dataVector[11].at("value").toShort();

    QByteArray unitLengthHex = dataVector[12].at("value").toUtf8();
    QByteArray unitLengthBytes;
    // 低字节在前的字节序
    for (int i = 0; i < unitLengthHex.size(); i += 2) {
        unitLengthBytes.append(unitLengthHex.mid(i, 2).toInt(nullptr, 16));
    }
//    // 高字节在前的字节序
//    for (int i = unitLengthHex.size() - 2; i >= 0; i -= 2) {
//        unitLengthBytes.append(unitLengthHex.mid(i, 2).toInt(nullptr, 16));
//    }

    heartbeatPacket.unitLength = unitLengthBytes;

    // 设置timestamp,需要将16进制字符串转换为QByteArray
    QByteArray timestampHex = dataVector[13].at("value").toUtf8();
    QByteArray timestampBytes;

    if (reverseBytes) {
        // 高字节在前的字节序
        for (int i = timestampHex.size() - 2; i >= 0; i -= 2) {
            timestampBytes.append(timestampHex.mid(i, 2).toInt(nullptr, 16));
        }
    } else {
        // 低字节在前的字节序
        for (int i = 0; i < timestampHex.size(); i += 2) {
            timestampBytes.append(timestampHex.mid(i, 2).toInt(nullptr, 16));
        }
    }

    heartbeatPacket.timestamp = timestampBytes;

    // 设置deviceId,需要将16进制字符串转换为QByteArray
    QByteArray deviceIdHex = dataVector[14].at("value").toUtf8();
    QByteArray deviceIdBytes;

    if (reverseBytes) {
        // 高字节在前的字节序
        for (int i = deviceIdHex.size() - 2; i >= 0; i -= 2) {
            deviceIdBytes.append(deviceIdHex.mid(i, 2).toInt(nullptr, 16));
        }
    } else {
        // 低字节在前的字节序
        for (int i = 0; i < deviceIdHex.size(); i += 2) {
            deviceIdBytes.append(deviceIdHex.mid(i, 2).toInt(nullptr, 16));
        }
    }

    heartbeatPacket.deviceId = deviceIdBytes;
}

bool MainWindow::LoadXmlContent(QString FileName)
{

    QString FilePath = m_selectedFolderPath + "/" + FileName + ".xml";

    QFile file(FilePath); // 替换为您实际的文件路径
        if (!file.open(QIODevice::ReadOnly)) {
            qDebug() << "Can not open file。";
            return false;
        }

        QDomDocument document;
        if (!document.setContent(&file)) {
            qDebug() << "无法将文件解析为DOM树。";
            file.close();
            return false;
        }
        file.close();

        dataVector.clear();
        QDomElement root = document.firstChildElement(); // 获取根元素

            // 遍历所有子元素
            QDomNodeList elements = root.childNodes();
//            for (int i = 0; i < elements.count(); i++) {
//                    QDomNode elementNode = elements.at(i);
//                    // 检查节点是否为元素。
//                    if (elementNode.isElement()) {
//                        QDomElement element = elementNode.toElement();

//                        QDomNodeList childNodes = element.childNodes();
//                        for (int j = 0; j < childNodes.count(); j++) {
//                            QDomNode childNode = childNodes.at(j);
//                            if (childNode.isElement()) {
//                                QDomElement childElement = childNode.toElement();
//                                qDebug() << childElement.nodeName() << ":" << childElement.text();
//                            }
//                        }
//                    }
//            }
            for (int i = 0; i < elements.count(); i++) {
                    QDomNode elementNode = elements.at(i);
                    // 检查节点是否为元素。
                    if (elementNode.isElement()) {
                        QDomElement element = elementNode.toElement();

                        QDomNodeList childNodes = element.childNodes();

                        // 创建一个字典来存储键值对
                        std::map<QString, QString> dataMap;

                        for (int j = 0; j < childNodes.count(); j++) {
                            QDomNode childNode = childNodes.at(j);
                            if (childNode.isElement()) {
                                QDomElement childElement = childNode.toElement();
//                                QString key = childElement.nodeName();
                                QString key = childElement.nodeName();
                                // 将键的第一个字母转换为小写
                                if (!key.isEmpty()) {
                                    key[0] = key[0].toLower();
                                }
                                QString value = childElement.text();
                                // 将键值对存入字典
                                dataMap[key] = value;
                            }
                        }

                        // 将字典存入vector
                        dataVector.push_back(dataMap);
                    }
                }

                // 打印存储的数据
                for (const auto& data : dataVector) {
                    for (const auto& pair : data) {
                        qDebug() << pair.first << ":" << pair.second;
                    }
                    qDebug() << "-------------------";
                }
}

void MainWindow::onSendButtonClicked()
{
    LoadXmlContent("心跳报文");
    convertVectorToHeartbeatPacket();
    // 发送心跳报文到广播地址
    sendHeartbeat(QHostAddress::Broadcast, 12345);
}
相关推荐
知识中的海王3 分钟前
Python html 库用法详解
开发语言·python
獨枭20 分钟前
配置 macOS 上的 Ruby 开发环境
开发语言·macos·ruby
飞由于度26 分钟前
C#中清空DataGridView的方法
开发语言·c#
朝朝又沐沐1 小时前
基于算法竞赛的c++编程(18)string类细节问题
开发语言·c++·算法
黄雪超1 小时前
JVM——对象模型:JVM对象的内部机制和存在方式是怎样的?
java·开发语言·jvm
爱学习的capoo2 小时前
matlab自控仿真【第一弹】❀传递函数和输出时域表达式
开发语言·matlab
EverBule2 小时前
Python 训练 day46
开发语言·python
蓝婷儿3 小时前
6个月Python学习计划 Day 18 - 项目实战 · 学生成绩管理系统(OOP版)
开发语言·python·学习
HINOTOR_3 小时前
DAY 25 异常处理
开发语言·python
yorushika_3 小时前
python打卡训练营打卡记录day49
开发语言·python·tensorboard·cbam