Отправка UDP-пакета фиксированного размера - PullRequest
0 голосов
/ 11 октября 2018

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

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

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

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

Допустим, например, что числа равны 2, 0 и 14829735431805717965. В настоящее время я делаю эти числа как переменные в поток ostring, который я читаю из этот поток должен преобразовать значения в 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 Ответ

0 голосов
/ 11 октября 2018

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

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

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

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

Когда я делаю sizeof (результат) и 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), ...);
...