Отправить Структуру поплавков через UDP - PullRequest
1 голос
/ 31 октября 2019

Итак, у меня есть структура чисел в Python, которую я посылаю через UDP:

lat = 14.566545
lon = 13.435456
alt = 3.5657732

coord_struct = struct.pack('fff', lat, lon, alt)
udp_sock.sendto(coord_struct,(UDP_IP,UDP_PORT_SEND))

программе, написанной в C, которая должна получить структуру и работать с ней:

typedef struct coords{ 
         float latitude; 
         float longitude; 
         float altitude;
} GEO_POS;

GEO_POS coord_struct;

recv_len = recvfrom(udp_fd, coord_struct, sizeof(coord_struct), 0, (struct sockaddr*) &si_other, &si_slen);

printf("lat: %f; lon: %f; alt: %f", coord_struct.latitude, coord_struct.longitude, coord_struct.altitude);

Но полученные данные неверны, например: 47.88980 получено как 5469892474000000000000000.

Нужно ли сериализовать struct, чтобыотправьте, если да, то как?

Есть ли лучший способ сделать это?

Спасибо за помощь!

1 Ответ

1 голос
/ 31 октября 2019

Прежде всего, вы пропускаете знак & перед coord_struct в вызове на recvfrom. Во-вторых ...

Правильный способ отправки двоичных данных по сети - преобразовать все в порядковый номер сети (big endian) при отправке и обратно в порядковый номер хоста при получении.

Отправка в Python:

lat = 14.566545
lon = 13.435456
alt = 3.5657732

coord_struct = struct.pack('!fff', lat, lon, alt)
# Notice the ! sign for network endianness.

udp_sock.sendto(coord_struct, (UDP_IP, UDP_PORT_SEND))

Получение в C:

struct coords { 
    float latitude; 
    float longitude; 
    float altitude;
};

struct coords coord_struct;
ssize_t recv_len;

// Assuming you have already correctly initialized the socket.

errno = 0;
recv_len = recvfrom(udp_fd, &coord_struct, sizeof(coord_struct), 0, (struct sockaddr*) &si_other, &si_slen);
// IMPORTANT ---------------^ notice the & here.

if (errno) {
    // There was an error with recvfrom, print it to
    // stderr to see what's wrong.
    perror("recvfrom failed");
    exit(1);
}

// Also check recv_len here, if recv_len < sizeof(coord_struct) you need
// to retry everything or try receiving more data.

// Convert from network endian to host endian:
coord_struct.latitude  = ntohl((uint32_t)coord_struct.latitude );
coord_struct.longitude = ntohl((uint32_t)coord_struct.longitude);
coord_struct.altitude  = ntohl((uint32_t)coord_struct.altitude );

printf(
    "lat: %f; lon: %f; alt: %f\n",
    coord_struct.latitude,
    coord_struct.longitude,
    coord_struct.altitude
);

Кроме того, вы также можете использовать MSG_WAITALL при вызове recvfrom, чтобы иметь меньше шансов получить меньше данных, чем ожидалось,Даже если структура, которую вы отправляете, не должна вызывать особых проблем, поскольку она очень мала и в основном всегда помещается в одну дейтаграмму UDP.

...