C++ 将int类型的结构放入Big-Endian中的ostream以转换为char*
我在C++ 将int类型的结构放入Big-Endian中的ostream以转换为char*,c++,sockets,serialization,network-programming,deserialization,C++,Sockets,Serialization,Network Programming,Deserialization,我在stdint.h中使用uintnt的struct实现了一个通过UDP套接字交换的消息 传递到UDP套接字的任何数据都必须是Big-Endian,当然也必须是char*或const-char*类型 我运行这个程序的系统是基于Little Endian的 我不熟悉序列化,基于以上的答案,我尝试了put()按与ostringstream相反的顺序对数据进行排序。(详见下面的代码) void put_u16_as_big(ostringstream&oss,uint16_t数据){ write((c
stdint.h
中使用uintnt
的struct
实现了一个通过UDP
套接字交换的消息
传递到UDP套接字的任何数据都必须是Big-Endian
,当然也必须是char*
或const-char*
类型
我运行这个程序的系统是基于Little Endian的
我不熟悉序列化,基于以上的答案,我尝试了put()
按与ostringstream
相反的顺序对数据进行排序。(详见下面的代码)
void put_u16_as_big(ostringstream&oss,uint16_t数据){
write((const char*)和data,sizeof(data));
如果(是大的吗?){
write((const char*)和data,sizeof(data));
}
否则{
常量字符*ptr=(常量字符*)&数据;
无符号整数s=sizeof(数据);
for(无符号整数i=0;i
但是,当我将struct中的所有数据放在ostringstream
的一个实例中并调用str()
方法时,数据的大小不是它应该的大小(小于8字节*2+8字节*3*所有服务器的数量,如上表所示),并且data()
方法从该字符串中进一步缩小(到8)
最后,当在另一侧接收时,大小为1
如何将结构序列化为char*
,并在不丢失任何数据的情况下发送和接收
struct
包含类型为uint16\u t
和uint32\u t
的字段,以及另一个结构的向量(用于服务器列表),该结构还包含uint16\u t
、uint32\u t
和int16\u t
请帮帮我。我已经努力解决这个问题好几天了,但是运气不好
谢谢。使用套接字API
htons()
(主机到网络短)和htonl()
(主机到网络长)函数将多字节整数从本地计算机的本机端号转换为网络字节顺序(big-endian)。在big-endian系统上,该操作是不可操作的。在little-endian系统上,字节交换。您可以使用ntohs()
(网络到主机短)和ntohl()
(网络到主机长)将多字节整数从网络字节顺序转换为本地计算机的本机endian
请注意,有些函数,如inet\u addr()
、gethostbyname()
和getaddrinfo()
报告的IPv4地址已按网络字节顺序排列,因此不要对这些值使用htonl()
和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
在接收端进行反向操作。使用
recvfrom()
接收消息数据,然后根据需要调用ntoh…()
转换消息的多字节整数,然后再处理消息。ostringstream
是完全错误的方法,甚至不要查看它。这不是序列化问题,这是字节尾数问题,这正是hton…()
和ntoh…()
所要处理的。不,您不能将向量
放入发送的结构中。不过,固定长度的数组可以工作。只要确保在调用sendto()
时,根据服务器的数量指定正确的消息大小,例如sizeof(header)+6+(sizeof(server)*numberOfServers)
,不要使用sizeof(msg)
。6是前3个字段的大小-更新字段的数量
,服务器端口
,和服务器IP
-在每服务器字段之前。是的,只要考虑到未使用的字段,就可以将未使用的字段留空。是的,应该是8,而不是6,对不起。但是不可以,除非您发送的服务器数量与sRouteUpdateMsg
实际容纳的最大服务器数量相同,否则传递给sendto()
的消息大小不会是sizeof(sRouteUpdateMsg)
的完整大小。servers
数组是sRouteUpdateMsg
的一部分,并将由sizeof>计算完整大小(sRouteUpdateMsg)
。这就是为什么您必须将sRouteUpdateMsg
的内容计算到服务器
数组,但不包括该数组,然后分别计算实际发送的服务器
数组中的项目数。我之所以一直提到一个单独的标题,是因为您的图表说明:“数据部分的消息格式为”,这意味着有一个消息头与您提供的图表分开描述。
#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), ...);
sendto(..., (char*)&msg, offsetof(sRouteUpdateMsg, servers)+(sizeof(sRouteUpdateServer)*numberOfServers), ...);