Конвертировать данные в обратный порядок

Я использую WinSock для отправки пакетов UDP на сервер, мне нужно отправить данные с прямым порядком байтов. Я не уверен, как преобразовать порядок байтов моей структуры перед отправкой.

У меня есть такая структура:

struct ConnectIn
{
std::int64_t ConnectionID = 0x41727101980;
std::int32_t Action = 0;
std::int32_t TransactionID;

ConnectIn(std::int32_t transactionID)
{
TransactionID = transactionID;
}
};

И на данный момент я отправляю так:

ConnectIn msg(123);
int len = sizeof(msg);
int bytesSent = sendto(s, (char*)&msg, len, 0, (SOCKADDR*)&dest, sizeof(address));

Как я могу преобразовать порядок байтов msg на большой порядок байтов перед отправкой?

Если вам интересно, данные, которые я отправляю, предназначены для Протокол Bit Torrent UDP-трекер.

2

Решение

Если вы хотите сделать это вручную, то поменяйте местами каждого участника по отдельности. Вы преобразовываете элементы из порядка байтов хост-компьютера в порядок байтов сети. На Win32 htonll() для 64-битных целых чисел и htonl() для 32-битных целых чисел:

#include <Winsock2.h>

ConnectIn msg(123);

msg.ConnectionID = htonll(msg.ConnectionID);
msg.Action = htonl(msg.Action);
msg.TransactionID= htonl(msg.TransactionID);

Затем вы также можете отправить участников по отдельности, чтобы не полагаться на структуру структуры хост-системы. Windows ABI не добавляет в эту структуру никаких отступов, но, возможно, для какой-то другой структуры, которую вы используете, это делает. Итак, вот основная идея:

char buf[sizeof msg.ConnectionID + sizeof msg.Action + sizeof msg.TransactionID];
char *bufi = buf;

std::memcpy(bufi, &msg.ConnectionID, sizeof msg.ConnectionID);
bufi += sizeof msg.ConnectionID;
std::memcpy(bufi, &msg.Action, sizeof msg.Action);
bufi += sizeof msg.Action;
std::memcpy(bufi, &msg.TransactionID, sizeof msg.TransactionID);
bufi += sizeof msg.TransactionID;

int len = sizeof buf;
int bytesSent = sendto(s, buf, len, 0, (SOCKADDR*)&dest, sizeof(address));

Затем на принимающей стороне вы используете соответствующие ntoh*() функции для 64-разрядных и 32-разрядных типов для преобразования порядка следования байтов в сети в порядок байтов принимающего узла.

3

Другие решения

Да, сетевой порядок байтов (NBO) — это Big Endian, поэтому вам нужно найти способ отправить эту структуру в сеть.

То, что вы сейчас делаете, не сработает: вы отправляете всю структуру, но у получателя может быть другой порядок байтов, заполнение и так далее.
Самые простые варианты:

  • Отправка каждого поля с заданным протоколом макетом
  • Библиотеки третьей части, которые обрабатывают сериализацию: Google Protobuf является одним из наиболее распространенных.

Для первого варианта есть некоторые функции, которые позаботятся об этом в библиотеке Winsock2. Это:

  • (WSA) ntohT (Сеть к хосту t, где t может быть short а также unsigned)
  • (WSA) htonT (Хост к сети т, где т может быть short а также unsigned)

Функции WSA немного отличаются и только для Windows.


Руководство по сетевому программированию
Ссылка на Winsock

3

Одним из вариантов является преобразование каждого из чисел в отдельности

Для GCC:

int32_t __builtin_bswap32 (int32_t x)
int64_t __builtin_bswap64 (int64_t x)

Для MSVC:

unsigned short _byteswap_ushort(unsigned short value);
unsigned long _byteswap_ulong(unsigned long value);
unsigned __int64 _byteswap_uint64(unsigned __int64 value);
-1