【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();
}
代码说明:
- 数据结构使用
#pragma pack
确保紧凑内存布局,避免对齐问题 - 网络通信部分:
- 绑定到任意IPv4地址并加入指定组播组
- 设置端口复用选项支持多接收端
- 数据解析:
- 严格检查数据包长度
- 处理网络字节序到主机字节序的转换
- 支持double和float类型的字节序转换
- 数据展示:
- 时间戳转换为易读格式
- 结构化输出所有接收到的参数
注意事项:
- 发送端和接收端的数据结构定义必须完全一致
- 组播地址范围需使用标准组播地址(224.0.0.0~239.255.255.255)
- 实际应用中建议添加错误处理和数据校验机制
- 字节序转换方法需与发送端实际使用的字节序保持一致
- 时间戳单位需与发送端约定一致(示例中使用毫秒时间戳)
请根据实际网络环境和数据格式调整组播地址、端口号和数据结构定义。
作者:copoer