【QT】组播实现接收外引导数据

以下是一个使用Qt实现UDP组播接收外引导数据的示例代码,包含目标编号、时间戳、空间位置和姿态信息:

#include <QtNetwork>
#include <QDebug>

#pragma pack(push, 1)
struct GuidanceData {
    quint32 targetId;     // 目标编号(4字节)
    quint64 timestamp;    // 时间戳(8字节,毫秒)
    double x;             // X坐标(8字节)
    double y;             // Y坐标(8字节)
    double z;             // Z坐标(8字节)
    float yaw;            // 方向角(4字节)
    float pitch;          // 俯仰角(4字节)
};
#pragma pack(pop)

class MulticastReceiver : public QObject {
    Q_OBJECT
public:
    explicit MulticastReceiver(QObject *parent = nullptr) : QObject(parent) {
        udpSocket = new QUdpSocket(this);
        
        // 组播地址和端口配置
        const QHostAddress groupAddress = QHostAddress("239.255.43.21");
        const quint16 port = 45454;

        // 绑定到所有IPv4接口并加入组播组
        if (udpSocket->bind(QHostAddress::AnyIPv4, port, QUdpSocket::ShareAddress)) {
            if (udpSocket->joinMulticastGroup(groupAddress)) {
                qInfo() << "Joined multicast group:" << groupAddress.toString() << "port:" << port;
            } else {
                qWarning() << "Failed to join multicast group:" << udpSocket->errorString();
            }
        } else {
            qCritical() << "Binding failed:" << udpSocket->errorString();
        }

        connect(udpSocket, &QUdpSocket::readyRead, this, &MulticastReceiver::processDatagrams);
    }

private slots:
    void processDatagrams() {
        while (udpSocket->hasPendingDatagrams()) {
            QByteArray datagram;
            datagram.resize(udpSocket->pendingDatagramSize());
            QHostAddress sender;
            quint16 senderPort;
            
            udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
            
            if (datagram.size() != sizeof(GuidanceData)) {
                qWarning() << "Invalid datagram size:" << datagram.size() 
                          << "Expected:" << sizeof(GuidanceData);
                continue;
            }

            GuidanceData data;
            memcpy(&data, datagram.constData(), sizeof(GuidanceData));

            // 字节序转换(假设发送端使用网络字节序)
            data.targetId = qFromBigEndian(data.targetId);
            data.timestamp = qFromBigEndian(data.timestamp);
            
            // 处理double类型坐标
            data.x = convertDouble(data.x);
            data.y = convertDouble(data.y);
            data.z = convertDouble(data.z);
            
            // 处理float类型角度
            data.yaw = convertFloat(data.yaw);
            data.pitch = convertFloat(data.pitch);

            // 转换为可读时间格式
            QDateTime time = QDateTime::fromMSecsSinceEpoch(data.timestamp);
            
            // 输出解析结果
            qDebug().nospace() 
                << "\nTarget ID: " << data.targetId
                << "\nTimestamp: " << time.toString("yyyy-MM-dd HH:mm:ss.zzz")
                << "\nPosition ("
                << "\n  X: " << data.x
                << "\n  Y: " << data.y
                << "\n  Z: " << data.z << ")"
                << "\nOrientation ("
                << "\n  Yaw: " << data.yaw << "°"
                << "\n  Pitch: " << data.pitch << "°)";
        }
    }

private:
    QUdpSocket *udpSocket;

    // 网络字节序到主机字节序转换(double)
    double convertDouble(double value) {
        quint64 temp;
        memcpy(&temp, &value, sizeof(quint64));
        temp = qFromBigEndian(temp);
        memcpy(&value, &temp, sizeof(double));
        return value;
    }

    // 网络字节序到主机字节序转换(float)
    float convertFloat(float value) {
        quint32 temp;
        memcpy(&temp, &value, sizeof(quint32));
        temp = qFromBigEndian(temp);
        memcpy(&value, &temp, sizeof(float));
        return value;
    }
};

// 使用示例
int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    MulticastReceiver receiver;
    return a.exec();
}

代码说明:

  1. 数据结构使用#pragma pack确保紧凑内存布局,避免对齐问题
  2. 网络通信部分:
  3. 绑定到任意IPv4地址并加入指定组播组
  4. 设置端口复用选项支持多接收端
  5. 数据解析:
  6. 严格检查数据包长度
  7. 处理网络字节序到主机字节序的转换
  8. 支持double和float类型的字节序转换
  9. 数据展示:
  10. 时间戳转换为易读格式
  11. 结构化输出所有接收到的参数

注意事项:

  1. 发送端和接收端的数据结构定义必须完全一致
  2. 组播地址范围需使用标准组播地址(224.0.0.0~239.255.255.255)
  3. 实际应用中建议添加错误处理和数据校验机制
  4. 字节序转换方法需与发送端实际使用的字节序保持一致
  5. 时间戳单位需与发送端约定一致(示例中使用毫秒时间戳)

请根据实际网络环境和数据格式调整组播地址、端口号和数据结构定义。

作者:copoer

物联沃分享整理
物联沃-IOTWORD物联网 » 【QT】组播实现接收外引导数据

发表回复