在 C++ 中获取 UDP 数据,核心流程是:创建 Socket -> 绑定端口(Bind) -> 循环接收(Recvfrom) -> 按协议解析。
由于导航数据通常是结构化的(如二进制或十六进制),建议直接映射到 struct。
C++ 示例代码(Linux/Windows 通用逻辑)
这里以 Linux 环境为例,展示如何读取一个假设的导航数据包:
cpp
#include <iostream>
#include <vector>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
// 根据设备的通讯协议手册(报文格式)
// 1. 根据你的导航设备协议定义结构体 (注意对齐)
#pragma pack(push, 1)
struct NavData {
uint32_t header; // 包头
double lon; // 经度
double lat; // 纬度
float heading; // 航向角
// ... 其他字段
};
#pragma pack(pop)
int main() {
int port = 8080; // 组合导航发送数据的目标端口
int sockfd;
char buffer[1024];
// 2. 创建 UDP Socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("Socket creation failed");
return -1;
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY; // 监听所有网卡
servaddr.sin_port = htons(port);
// 3. 绑定端口
if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("Bind failed");
return -1;
}
std::cout << "Waiting for Nav Data on port " << port << "..." << std::endl;
while (true) {
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
// 4. 接收数据
int n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&cliaddr, &len);
if (n > 0) {
// 5. 解析数据 (假设收到的就是 NavData 结构)
if (n >= sizeof(NavData)) {
NavData* data = reinterpret_cast<NavData*>(buffer);
// 打印结果
std::cout << "Lon: " << data->lon << " Lat: " << data->lat
<< " Heading: " << data->heading << std::endl;
}
}
}
close(sockfd);
return 0;
}
关键点解析:
#pragma pack(1): 组合导航通常发送的是原始二进制流。这个指令防止 C++ 编译器在结构体中插入填充字节,确保内存布局与传感器发送的 协议文档 完全一致。INADDR_ANY: 如果你的电脑有多个网卡(比如网线连导航,WiFi上网),使用INADDR_ANY可以接收发往任何网卡的数据。- 大端/小端 (Endianness) : 多数现代导航设备(及 X86 电脑)使用小端模式。如果数据乱码,请检查协议是否要求使用
ntohl或ntohs进行字节序转换。 - 缓冲区大小 :
buffer应略大于设备发送的最长数据包。