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

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

心跳报文结构如下:

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();


};

代码如下:

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

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 要实现QtUDP通信源文件打包下载,可以按照以下步骤进行: 1. 首先,创建一个Qt应用程序工程,并添加所需的UDP通信相关的头文件和源文件。 2. 在Qt的主窗口界面,设计一个用户界面,包括一个文件选择框和一个下载按钮,用于选择要下载的源文件和触发下载操作。 3. 在代码,定义一个QUdpSocket对象,用于进行UDP通信。 4. 在下载按钮的信号槽函数,首先获取用户选择的源文件路径。 5. 然后,使用QUdpSocket对象的writeDatagram函数发送一个请求报文给UDP服务器,请求下载指定的源文件。可以使用协议规定的特定格式进行报文的封装,例如指定一个特定的操作码来表示下载请求。 6. 接下来,使用QUdpSocket对象监听UDP服务器发送回来的文件数据。 7. 在QUdpSocket的readyRead信号的槽函数,使用readDatagram函数读取UDP服务器发送数据包,并将其保存到本地。 8. 当接收UDP服务器发送的文件数据时,可以根据协议规定的格式解析数据,获取文件的内容,并将其保存到本地磁盘的指定位置。 9. 下载完成后,可以弹出一个对话框提示用户下载完成,并根据需要进行后的操作,例如打开下载的源文件等。 10. 最后,进行错误处理和资源清理的操作,释放相关的资源。 通过以上步骤,就可以实现在Qt通过UDP通信进行源文件打包下载的功能。在实际使用,还需要根据具体的需求进行一些调整和优化。 ### 回答2: 实现UDP通信源文件打包下载的方法如下: 首先,我们需要使用Qt框架的网络模块来创建一个UDP通信的客户端和服务端。 客户端: 1. 创建一个QUdpSocket对象来处理UDP报文的发送接收。 2. 绑定一个本地端口来接收服务端的响应。 3. 使用QFile类打开要下载的源文件。 4. 将文件的内容分割成一定大小的数据包,并使用QUdpSocket的writeDatagram函数将数据包发送给服务端。 5. 监听QUdpSocket的readyRead信号,以接收服务端的响应。 6. 接收服务端发送数据包,并将其写入一个新文件。 7. 循环执行步骤6,直到接收到服务端发送的结束标志。 8. 关闭QUdpSocket和QFile对象。 服务端: 1. 创建一个QUdpSocket对象来处理UDP报文的发送接收。 2. 绑定一个本地端口来接收客户端的请求。 3. 监听QUdpSocket的readyRead信号,以接收客户端的请求。 4. 接收客户端发送数据包,并将其写入一个文件。 5. 循环执行步骤4,直到接收到客户端发送的结束标志。 6. 关闭QUdpSocket。 在客户端和服务端之间传输文件时,可以使用文件分片的方式来进行传输和接收,即将文件分割成一定大小的数据包,以提高传输效率和稳定性。当充分利用UDP数据包的大小限制时,可以在一个数据包传输多个文件分片。 此外,为了确保数据的完整性和准确性,可以在发送数据包添加一些校验码或者序列号来进行检验和验证。 需要注意的是,UDP通信是一种不可靠的通信协议,因此在实现源文件打包下载时,客户端和服务端需要遵循一定的通信协议来保证数据的可靠性和一致性。例如,可以在每个数据包添加一个标志位来指示数据的开始和结束,以及数据包的序号来进行跟踪和验证。 总之,通过使用Qt的网络模块和UDP通信协议,我们可以实现源文件的打包下载功能,并且可以结合一些数据分片和校验机制来提高传输的稳定性和可靠性。 ### 回答3: Qt实现UDP通信源文件打包下载可以通过以下步骤实现: 1. 创建一个Qt项目,引入网络相关的头文件,如QUdpSocket。 2. 在主程序的入口函数创建一个QUdpSocket对象udpSocket。 3. 设置udpSocket对象的绑定端口号以及绑定地址(如果需要)。 4. 使用udpSocket对象的bind函数将socket与指定的端口号绑定。 5. 连接udpSocket对象的readyRead信号到对应的槽函数,用来接收数据。 6. 在槽函数使用udpSocket对象的readDatagram函数,读取接收到的数据,存储到本地文件。 7. 创建一个下载按钮,连接到对应的槽函数。 8. 在槽函数创建一个QUdpSocket对象downloadSocket。 9. 设置downloadSocket对象的绑定端口号以及绑定地址(如果需要)。 10. 使用downloadSocket对象的connectToHost函数连接到指定发送端地址和端口号。 11. 在按钮槽函数使用downloadSocket对象的writeDatagram函数发送请求数据包发送端。 12. 在槽函数使用downloadSocket对象的waitForReadyRead函数等待接收数据。 13. 接收发送端的回复后,使用downloadSocket对象的readDatagram函数读取回复的文件数据并存储到本地文件。 14. 下载完成后,关闭downloadSocket对象。 这样就实现了通过UDP通信进行源文件打包下载的功能。注意在发送端需要将源文件按照一定的协议打包数据包,以便接收端可以正确解析和保存文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天天进步2015

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值