data-serialization
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseData Serialization for Games
游戏数据序列化
Implement efficient serialization for low-latency game networking.
为低延迟游戏网络实现高效序列化。
Format Comparison
格式对比
| Format | Size | Speed | Schema | Use Case |
|---|---|---|---|---|
| Protobuf | Small | Fast | Required | Most games |
| FlatBuffers | Small | Fastest | Required | Real-time |
| MsgPack | Small | Fast | Optional | Flexible |
| JSON | Large | Slow | None | Debug |
| Custom Binary | Smallest | Fastest | Custom | Ultra-low latency |
| 格式 | 大小 | 速度 | 模式 | 适用场景 |
|---|---|---|---|---|
| Protobuf | 小 | 快 | 必填 | 大多数游戏 |
| FlatBuffers | 小 | 最快 | 必填 | 实时场景 |
| MsgPack | 小 | 快 | 可选 | 灵活场景 |
| JSON | 大 | 慢 | 无 | 调试场景 |
| 自定义二进制 | 最小 | 最快 | 自定义 | 超低延迟场景 |
Protocol Buffers
Protocol Buffers
protobuf
syntax = "proto3";
message PlayerState {
uint32 player_id = 1;
float x = 2;
float y = 3;
float z = 4;
uint32 health = 5;
}
message GameUpdate {
uint64 tick = 1;
repeated PlayerState players = 2;
}cpp
GameUpdate update;
update.set_tick(current_tick);
auto* player = update.add_players();
player->set_player_id(1);
player->set_x(pos.x);
std::string serialized;
update.SerializeToString(&serialized);protobuf
syntax = "proto3";
message PlayerState {
uint32 player_id = 1;
float x = 2;
float y = 3;
float z = 4;
uint32 health = 5;
}
message GameUpdate {
uint64 tick = 1;
repeated PlayerState players = 2;
}cpp
GameUpdate update;
update.set_tick(current_tick);
auto* player = update.add_players();
player->set_player_id(1);
player->set_x(pos.x);
std::string serialized;
update.SerializeToString(&serialized);Custom Binary Format
自定义二进制格式
cpp
struct PacketHeader {
uint16_t type;
uint16_t length;
uint32_t sequence;
};
struct PlayerUpdate {
uint32_t player_id;
float position[3];
uint16_t angle; // Compressed rotation
uint8_t flags;
};
void serialize(Buffer& buf, const PlayerUpdate& p) {
buf.write_u32(htonl(p.player_id));
for (int i = 0; i < 3; i++)
buf.write_float(p.position[i]);
buf.write_u16(htons(p.angle));
buf.write_u8(p.flags);
}cpp
struct PacketHeader {
uint16_t type;
uint16_t length;
uint32_t sequence;
};
struct PlayerUpdate {
uint32_t player_id;
float position[3];
uint16_t angle; // 压缩后的旋转角度
uint8_t flags;
};
void serialize(Buffer& buf, const PlayerUpdate& p) {
buf.write_u32(htonl(p.player_id));
for (int i = 0; i < 3; i++)
buf.write_float(p.position[i]);
buf.write_u16(htons(p.angle));
buf.write_u8(p.flags);
}Compression Techniques
压缩技术
| Technique | Savings | Complexity |
|---|---|---|
| Delta | 50-80% | Medium |
| Quantization | 30-50% | Low |
| LZ4 | 50-70% | Low |
| 压缩技术 | 压缩率 | 实现复杂度 |
|---|---|---|
| Delta | 50-80% | 中等 |
| 量化(Quantization) | 30-50% | 低 |
| LZ4 | 50-70% | 低 |
Troubleshooting
故障排查
Common Failure Modes
常见故障模式
| Error | Root Cause | Solution |
|---|---|---|
| Parse error | Version mismatch | Schema versioning |
| Large packets | No compression | Enable delta/LZ4 |
| Slow parsing | JSON in hot path | Use binary format |
| Corruption | Byte order | Use htonl/ntohl |
| 错误类型 | 根本原因 | 解决方案 |
|---|---|---|
| 解析错误 | 版本不兼容 | 模式版本控制 |
| 数据包过大 | 未启用压缩 | 启用Delta/LZ4压缩 |
| 解析缓慢 | 热路径使用JSON | 使用二进制格式 |
| 数据损坏 | 字节序问题 | 使用htonl/ntohl转换 |
Debug Checklist
调试检查清单
cpp
// Check serialized size
std::string data;
message.SerializeToString(&data);
std::cout << "Size: " << data.size() << " bytes\n";
// Validate roundtrip
Message parsed;
parsed.ParseFromString(data);
assert(parsed.id() == message.id());cpp
// 检查序列化后大小
std::string data;
message.SerializeToString(&data);
std::cout << "Size: " << data.size() << " bytes\n";
// 验证往返序列化
Message parsed;
parsed.ParseFromString(data);
assert(parsed.id() == message.id());Unit Test Template
单元测试模板
cpp
TEST(Serialization, RoundTrip) {
PlayerState original{1, 10.0f, 20.0f, 30.0f, 100};
std::string data;
original.SerializeToString(&data);
PlayerState parsed;
parsed.ParseFromString(data);
EXPECT_EQ(original.player_id(), parsed.player_id());
EXPECT_FLOAT_EQ(original.x(), parsed.x());
}cpp
TEST(Serialization, RoundTrip) {
PlayerState original{1, 10.0f, 20.0f, 30.0f, 100};
std::string data;
original.SerializeToString(&data);
PlayerState parsed;
parsed.ParseFromString(data);
EXPECT_EQ(original.player_id(), parsed.player_id());
EXPECT_FLOAT_EQ(original.x(), parsed.x());
}Resources
资源
- - Schema templates
assets/ - - Format benchmarks
references/
- - 模式模板
assets/ - - 格式基准测试
references/