Отправка пакета UDP с фиксированным размером

Я пишу программу на C ++ для отправки пакета UDP длиной 10 байт. Пакет состоит из трех частей:

1 байт - одно число от 0 до 9

1 байт - одно число от 0 до 2

8 байтов - число от 0 до максимального значения uint64

Например, цифры равны 2, 0 и 14829735431805717965. То, что я делаю в эти моменты, отправляет эти числа в качестве переменных в ostringstream, которые я прочитал из этого потока, должен преобразовать значения в ASCII для сериализации.

ostringstream str1;
uint8_t byte1 = 2;
uint8_t byte2 = 0;
uint64_t bytes = 14829735431805717965;


str1 << byte1<< byte2 << bytes;
string result = str1.str();
const char *pchar = result.c_str();

Вышеприведенный код демонстрирует мой процесс, чтобы сделать его совместимым с методом sendto (). Однако, когда я делаю sizeof(str1) я получаю 152, даже думая отдельно, эти переменные добавляют до 10 байтов (1 + 1 + 8). Когда я делаю sizeof(result) и sizeof(pchar) я получаю 28 и 4 соответственно - ничего отдаленно напоминающего мои 10 байт. Я могу только понять, что мой способ сделать это неверно - это uint64_t bytes каждый номер, преобразованный в отдельный ASCII, который добавляет до 150 или что-то еще? Я искал похожие проблемы, но безуспешно.

Всего 1 ответ


Однако, когда я делаю sizeof (str1), я получаю 152

Это связано с тем, что вы получаете размер байта самого объекта ostringstream . ostringstream есть много элементов данных, кроме указателя на данные символа. Вы ищете размер байта фактических символов. ostringstream не предоставляет этот размер напрямую.

даже мысли отдельно, эти переменные составляют до 10 байтов (1 + 1 + 8).

Необработанные переменные, да. Но, используя operator<< , вы сериализуете свои значения в string , где каждая цифра становится ее собственным символом в строке, поэтому общий размер байта конечных символьных данных будет больше 22, а не 10.

Когда я делаю sizeof (result) и sizeof (pchar), я получаю 28 и 4 соответственно

Опять же, поскольку вы получаете размер байта самого string объекта (который также имеет другие элементы данных помимо указателя на данные символа) и размер байта самого исходного указателя. Вы ищете размер байта символьных данных, на которые указывает внутренняя string .

result.c_str() вернет указатель на фактические данные символа, а result.size() предоставит вам правильный размер байта для этих данных.

Я могу только понять, что мой способ сделать это неправильно как-то

Использование operator<< является совершенно неправильным решением в этой ситуации. Чтобы поместить двоичные данные в ostream , используйте его метод write() , например:

uint8_t byte1 = 2;
uint8_t byte2 = 0;
uint64_t bytes = 14829735431805717965;

ostringstream str1;
str1.write(reinterpret_cast<char*>(&byte1), sizeof(byte1));
str1.write(reinterpret_cast<char*>(&byte2), sizeof(byte2));
str1.write(reinterpret_cast<char*>(&bytes), sizeof(bytes));

string result = str1.str();
sendto(..., result.c_str(), result.size(), ...);

Лично я бы предложил использовать байт-выровненную структуру:

#pragma pack(push, 1)
struct packet {
    uint8_t byte1;
    uint8_t byte2;
    uint64_t bytes;
};
#pragma pack(pop)

packet p;
p.byte1 = 2;
p.byte2 = 0;
p.bytes = 14829735431805717965;

sendto(..., reinterpret_cast<char*>(&packet), sizeof(packet), ...);

Или, что еще хуже, просто используйте простой массив байтов:

char packet[10];

uint8_t byte1 = 2;
uint8_t byte2 = 0;
uint64_t bytes = 14829735431805717965;

memcpy(&packet[0], &byte1, sizeof(byte1));
memcpy(&packet[1], &byte2, sizeof(byte2));
memcpy(&packet[2], &bytes, sizeof(bytes));
/* or:
*reinterpret_cast<uint8_t*>(&packet[0]) = byte1;
*reinterpret_cast<uint8_t*>(&packet[1]) = byte2;
*reinterpret_cast<uint64_t*>(&packet[2]) = bytes;
*/

sendto(..., packet, sizeof(packet), ...);

Есть идеи?

10000