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);
}
相关推荐
IT书架5 分钟前
golang面试题
开发语言·后端·golang
初遇你时动了情22 分钟前
uniapp 城市选择插件
开发语言·javascript·uni-app
zongzi_4941 小时前
二次封装的天气时间日历选择组件
开发语言·javascript·ecmascript
kikyo哎哟喂1 小时前
Java 代理模式详解
java·开发语言·代理模式
duration~2 小时前
SpringAOP模拟实现
java·开发语言
一条晒干的咸魚2 小时前
【Web前端】实现基于 Promise 的 API:alarm API
开发语言·前端·javascript·api·promise
就爱六点起2 小时前
C/C++ 中的类型转换方式
c语言·开发语言·c++
我明天再来学Web渗透2 小时前
【SQL50】day 2
开发语言·数据结构·leetcode·面试
猫猫的小茶馆2 小时前
【C语言】指针常量和常量指针
linux·c语言·开发语言·嵌入式软件
DanielYQ2 小时前
LCR 001 两数相除
开发语言·python·算法