发送固定大小的 UDP 数据包

Sending a fixed size UDP packet

我正在编写一个 C++ 程序来发送一个 10 字节的 UDP 数据包。 数据包由三部分组成:

1 字节 - 0-9 的单个数字

1 字节 - 0-2 中的单个数字

8 个字节 - 从 0 到 uint64 最大值的数字

比方说数字是 2、0 和 14829735431805717965。 我现在正在做的是将这些数字作为变量发送到 ostringstream,我从 this thread 读取的应该将值转换为 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 或什么? 我四处寻找类似的问题,但无济于事。

However when I do sizeof(str1) I get 152

那是因为您获取的是 ostringstream 对象本身的字节大小。 ostringstream 除了指向字符数据的指针外,还有很多数据成员。您正在寻找实际字符数据的字节大小。 ostringstream 不直接提供该尺寸。

even thought separately those variables add up to 10 bytes (1+1+8).

原始变量可以,是的。但是,通过使用 operator<<,您将它们的值序列化为 string,其中每个数字在字符串中成为其自己的字符,因此最终字符数据的总字节大小将更像是 22 , 而不是 10.

When I do sizeof(result) and sizeof(pchar) I get 28 and 4 respectively

同样,因为您正在获取 string 对象本身的字节大小(除了指向字符数据的指针之外,它还有其他数据成员),以及原始指针本身的字节大小.您正在查找 string 内部指向的字符数据的字节大小。

result.c_str() 将 return 指向实际字符数据的指针,result.size() 将为您提供该数据的正确字节大小。

I can only figure my method of doing this is wrong somehow

在这种情况下使用 operator<< 是完全错误的解决方案。要将 binary 数据放入 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), ...);