如何创建特定大小的消息以通过 C++ 中的 UDP 套接字发送?
How to create specific size message to send via UDP socket in C++?
我正在尝试编写一个小型应用程序,它将 "concatenate" 一堆不同大小的整数变量(uint8、uint16、uint32)转换为将通过 UDP 套接字发送的 128 字节消息。
在接收方,我想将消息拆分回单个整数并存储它们以供进一步处理。现在我假设字节顺序不会成为问题。
我能得到一些关于如何连接 int 变量并随后从 128 字节消息中提取它们的提示吗?
您可以创建一个字符缓冲区前缀,该前缀将在每个整数之前定义要读取的整数类型,这样您就可以读取所定义整数的正确大小。
例如:在每个整数前面加上一个代表整数的字符。第一个字节将包含您将解释为 an 的字符,它可以是任何表示整数的 ascii 字符。
array == [byte][byte-8bit][byte][2 byte-16bit][byte][4 byte -32bit]...
UINT8 = 'a'
UINT16 = 'b'
UINT32 = 'c' 或者任何你想要的 ascii 代码...我使用 a,b,c 所以它是一个你可以在调试器中读取的可读字符
然后您必须构建要使用前缀发送的数组,以便您知道下一次读取的大小。
array = [a0b00c0000a0b00c0000]等,可以使用memcpy
构建数组
然后您可以发送整个 128 字节的数据包
确保你读到的正好是128个字节,然后你就可以解构了,记住读的时候一定要检查从socket中读到的量,继续读直到收到正确的量。 -- 有时读取不会 return 您期望的正确字节数。
当您收到数据包时,您可以使用 header 解构数据包,并且根据您收到的 header,您可以删除正确的整数和大小,以及 header正确大小的应该很容易解构。
还要记住 UDP 是有损的,因此您可能会丢失数据包
现在还请记住,如果您构造的数据包每次都不完全等于 128 个字节,您将需要添加另一个字节,该字节相当于一个整数,它会告诉您确切发送了多少字节...122。 .126..127 等,并将其作为另一边的第一个 header 阅读。
那么,假设您希望按以下顺序接收数据:
int32_t header; int8_t opcode; int16_t args[32]; int32_t clients[2]; ...
这只是一个示例,参数可以是您实际任务中的任何参数。
您可以将这些参数包装到 struct
或 class
中。我更喜欢这里的 struct
,因为看起来您并不真的需要创建构造函数、访问说明符或 class
可以提供的任何其他花哨的东西。所以,类似的东西:
#pragma pack(push, 1)
struct DataFromMyHardware {
int32_t header;
int8_t opcode;
int16_t args[32];
int32_t clients[2];
...
};
#pragma pack(pop)
pragma
这里用来告诉编译器不要优化结构中变量的放置或对齐,所以它会按原样存储在内存中。
这样,您可以在发件人上使用它:
DataFromMyHardware buffer;
buffer.header = 0xDEADBEEF;
buffer.opcode = 42;
...
send(socket, &buffer, sizeof(buffer), 0);
接收方:
DataFromMyHardware buffer;
recv(socket, (void*)&buffer, sizeof(buffer), 0);
旁注:您的设备很可能使用网络字节顺序,因此您可能希望在接收方使用 nhohl/ntohs
并在发送方使用 htonl/htons
。
我正在尝试编写一个小型应用程序,它将 "concatenate" 一堆不同大小的整数变量(uint8、uint16、uint32)转换为将通过 UDP 套接字发送的 128 字节消息。
在接收方,我想将消息拆分回单个整数并存储它们以供进一步处理。现在我假设字节顺序不会成为问题。
我能得到一些关于如何连接 int 变量并随后从 128 字节消息中提取它们的提示吗?
您可以创建一个字符缓冲区前缀,该前缀将在每个整数之前定义要读取的整数类型,这样您就可以读取所定义整数的正确大小。
例如:在每个整数前面加上一个代表整数的字符。第一个字节将包含您将解释为 an 的字符,它可以是任何表示整数的 ascii 字符。
array == [byte][byte-8bit][byte][2 byte-16bit][byte][4 byte -32bit]...
UINT8 = 'a' UINT16 = 'b' UINT32 = 'c' 或者任何你想要的 ascii 代码...我使用 a,b,c 所以它是一个你可以在调试器中读取的可读字符
然后您必须构建要使用前缀发送的数组,以便您知道下一次读取的大小。
array = [a0b00c0000a0b00c0000]等,可以使用memcpy
构建数组然后您可以发送整个 128 字节的数据包
确保你读到的正好是128个字节,然后你就可以解构了,记住读的时候一定要检查从socket中读到的量,继续读直到收到正确的量。 -- 有时读取不会 return 您期望的正确字节数。
当您收到数据包时,您可以使用 header 解构数据包,并且根据您收到的 header,您可以删除正确的整数和大小,以及 header正确大小的应该很容易解构。
还要记住 UDP 是有损的,因此您可能会丢失数据包
现在还请记住,如果您构造的数据包每次都不完全等于 128 个字节,您将需要添加另一个字节,该字节相当于一个整数,它会告诉您确切发送了多少字节...122。 .126..127 等,并将其作为另一边的第一个 header 阅读。
那么,假设您希望按以下顺序接收数据:
int32_t header; int8_t opcode; int16_t args[32]; int32_t clients[2]; ...
这只是一个示例,参数可以是您实际任务中的任何参数。
您可以将这些参数包装到 struct
或 class
中。我更喜欢这里的 struct
,因为看起来您并不真的需要创建构造函数、访问说明符或 class
可以提供的任何其他花哨的东西。所以,类似的东西:
#pragma pack(push, 1)
struct DataFromMyHardware {
int32_t header;
int8_t opcode;
int16_t args[32];
int32_t clients[2];
...
};
#pragma pack(pop)
pragma
这里用来告诉编译器不要优化结构中变量的放置或对齐,所以它会按原样存储在内存中。
这样,您可以在发件人上使用它:
DataFromMyHardware buffer;
buffer.header = 0xDEADBEEF;
buffer.opcode = 42;
...
send(socket, &buffer, sizeof(buffer), 0);
接收方:
DataFromMyHardware buffer;
recv(socket, (void*)&buffer, sizeof(buffer), 0);
旁注:您的设备很可能使用网络字节顺序,因此您可能希望在接收方使用 nhohl/ntohs
并在发送方使用 htonl/htons
。