Eri*_*off 7 c++ struct cross-platform data-structures
我正在编写一个具有网络功能的跨平台游戏(使用SFML和RakNet),我已经到了我已经在我的Ubuntu服务器上编译服务器并让我的Mac上运行客户端的地步.所有的开发都在我的Mac上完成,所以我最初一直在测试服务器,它运行良好.
我struct
通过网络发送s然后简单地将它们从char *
(例如)转发回来inet::PlayerAdded
.现在这一直很好(大部分),但我的问题是:这总是有效吗?这似乎是一种非常脆弱的方法.例如,即使在其他平台上,结构体的布局也一样吗?你会推荐什么?
#pragma pack(push, 1)
struct Player
{
int dir[2];
int left;
float depth;
float elevation;
float velocity[2];
char character[50];
char username[50];
};
// I have been added to the game and my ID is back
struct PlayerAdded: Packet
{
id_type id;
Player player;
};
#pragma pack(pop)
Run Code Online (Sandbox Code Playgroud)
如果(除其他事项外)您尝试从小端机器到大端机器执行此操作,这将无效,因为正确的int
表示将在两者之间反转.
如果您的结构的对齐或包装在不同机器之间发生变化,这也可能会失败.如果你有一些64位机器而一些是32位机器怎么办?
您需要使用适当的便携式序列化库,如Boost.Serialization或Google Protocol Buffers,以确保您拥有可以独立于硬件成功解码的有线协议(也称为可传输数据格式).
关于Protocol Buffers的好处是,您可以使用与protobuf流兼容的ZLIB兼容流透明地压缩数据.我实际上做到了这一点,效果很好.我想其他装饰器流可以以类似的方式使用,以根据需要增强或优化您的基本线程协议.
像许多其他答案一样,如果可以避免,我建议不要发送原始二进制数据.像Boost serial或Google Protobuf这样的东西可以在没有太多开销的情况下做得很好.
但是你当然可以创建跨平台的二进制结构,它始终是完成的,并且是一种非常有效的数据交换方式.在该数据上分层"结构"是有道理的.但是你必须非常小心布局,幸运的是大多数编译器为你提供了很多选择."打包"就是这样一种选择,并且需要处理很多.
您还需要注意数据大小.简单包括stdint.h并使用固定大小类型uint32_t
.请注意浮点值,因为并非所有体系结构都将共享相同的值,因为它们可能会执行32位浮点运算.同样对于endianess,大多数架构都会使用相同的,如果不是,你可以简单地在不同的客户端上翻转它.