我在UDP
套接字上交换了一条消息,我使用struct
中uintN_t
的{{1}}实施了这些套接字。
传递给UDP套接字的任何数据都必须在stdint.h
中,当然,还需要Big Endian
或char *
类型。
我运行此程序的系统是基于Little Endian的。
我不熟悉序列化,并且基于SO的答案,我尝试const char *
以相反的顺序将数据发送到put()
来执行此操作。 (详见下面的代码)
ostringstream
但是,当我将struct中的所有数据放入void put_u16_as_big(ostringstream& oss, uint16_t data) {
oss.write((const char *)&data, sizeof(data));
if (is_big_endian()) {
oss.write((const char *)&data, sizeof(data));
}
else {
const char * ptr = (const char *)&data;
unsigned int s = sizeof(data);
for(unsigned int i=0; i < s; ++i) {
oss.put(ptr[s-1-i]);
}
}
}
的实例并调用ostringstream
方法时,数据的大小不是它应该的大小(小于8字节* 2 + 8字节* 3 *所有服务器的数量,如上表所示),以及该字符串中的str()
方法,它进一步缩小(至8)。
最后,当在另一方收到它时,大小为1。
如何将我的结构序列化为data()
并发送和接收而不会丢失任何数据?
char *
包含struct
和uint16_t
类型的字段,以及另一个包含uint32_t
,{{1 }和uint16_t
。
请帮帮我。我几天都在努力解决这个问题,但没有运气......
谢谢。
答案 0 :(得分:2)
使用套接字API htons()
(主机到网络短)和htonl()
(主机到网络长)函数将多字节整数从本地机器的本机端转换为网络字节顺序(big端)。在大端系统上,操作是无操作的。在little-endian系统上,字节被交换。您可以使用ntohs()
(网络到主机短路)和ntohl()
(网络到主机长)将多字节整数从网络字节顺序转换为本地机器的本机端。
请注意,某些功能(如inet_addr()
,gethostbyname()
和getaddrinfo()
会报告已经按网络字节顺序排列的IPv4地址,因此请勿使用htonl()
和{{ 1}}在这些值上,按原样使用它们。
然后,定义一个字节对齐的ntohl()
来保存您的邮件数据,然后将其按原样传递给struct
,不要将其转换为sendto()
。不要被ostringstream
期望sendto()
的事实所困惑,这只是出于历史原因。它实际上需要原始字节,而不是字符串。
试试这个:
char*
#pragma pack(push, 1) // or your compiler's equivalent
struct sMsgHeader
{
// General Message header fields here...
};
// ...
struct sRouteUpdateServer
{
uint32_t serverIP;
uint16_t serverPort;
uint16_t reserved;
uint16_t serverID;
uint16_t cost;
};
struct sRouteUpdateMsg
{
sMsgHeader header;
uint16_t numUpdateFields;
uint16_t serverPort;
uint32_t serverIP;
sRouteUpdateServer servers[some max value here];
};
#pragma pack(pop) // or your compiler's equivalent
或者,如果您的编译器支持sRouteUpdateMsg msg;
// fill msg.header as needed...
msg.numUpdateFields = htons(...);
msg.serverPort = htons(...);
msg.serverIP = ...;
for (int i = 0; i < numberOfServers; ++i)
{
msg.servers[i].serverIP = ...;
msg.servers[i].serverPort = htons(...);
msg.servers[i].reserved = 0;
msg.servers[i].serverID = htons(...);
msg.servers[i].cost = htons(...);
}
//...
sendto(..., (char*)&msg, sizeof(sMsgHeader)+8+(sizeof(sRouteUpdateServer)*numberOfServers), ...);
(或您自己编写):
offsetof()
在接收方做相反的事情。使用sendto(..., (char*)&msg, offsetof(sRouteUpdateMsg, servers)+(sizeof(sRouteUpdateServer)*numberOfServers), ...);
接收消息数据,然后根据需要调用recvfrom()
转换消息的多字节整数,然后再处理消息。