cdr序列化与反序列化

发布于:2025-07-17 ⋅ 阅读:(21) ⋅ 点赞:(0)

CDR(Common Data Representation)是 CORBA(Common Object Request Broker Architecture)中用于跨平台数据交换的二进制序列化格式。它解决了不同系统间(不同字节序、对齐方式)的数据兼容性问题。以下是 CDR 序列化和反序列化的详细解析:


CDR 核心特性

  1. 平台无关性
    • 自动处理字节序(大端/小端)
    • 处理数据对齐(如 4 字节对齐)
  2. 类型安全
    • 支持 CORBA IDL 定义的所有数据类型
  3. 无自描述性
    • 依赖 IDL 接口定义进行解析(无元数据)

CDR 序列化流程

以结构体 Person 为例:

// IDL 定义
struct Person {
    long id;      // 4 字节整数
    string name;  // 变长字符串
};
序列化步骤
  1. 写字节序标志(1 字节)

    • 0x00 表示大端序,0x01 表示小端序
  2. 序列化 id(4 字节整数)

    • 按字节序写入(如 id=4487 → 大端序 0x00 0x00 0x11 0x87
  3. 序列化字符串 name

    • 先写长度(4 字节无符号长整型)
      • "Alice" → 长度 50x00 0x00 0x00 0x05
    • 再写字符串内容(含结束符 \0
      • A l i c e \00x41 0x6C 0x69 0x63 0x65 0x00
    • 填充对齐:总长度按 4 字节对齐
      • 示例:6 字节内容 → 填充 2 字节 → 0x00 0x00
  4. 最终字节流(大端序示例):

| 字节序 | id (4B)   | 长度 (4B) | 字符串内容 (6B) | 填充 (2B) |
|--------|-----------|-----------|-----------------|-----------|
| 0x00   | 00 00 11 87 | 00 00 00 05 | 41 6C 69 63 65 00 | 00 00     |

CDR 反序列化流程

  1. 读字节序标志

    • 检测 0x00/0x01,决定后续解析方式
  2. 反序列化 id

    • 读取 4 字节 → 按字节序转换 → 0x00001187 = 4487
  3. 反序列化字符串

    • 读长度(4 字节)→ 5
    • 读内容(5+1 字节)→ "Alice\0"
    • 跳过填充字节(2 字节)

字节序处理机制

// 序列化时的伪代码
void serialize_long(long value, CDRStream& stream) {
    if (stream.is_big_endian()) {
        write_bytes(htobe32(value));  // 转大端序
    } else {
        write_bytes(htole32(value));  // 转小端序
    }
}

// 反序列化时的伪代码
long deserialize_long(CDRStream& stream) {
    bytes = read_bytes(4);
    if (stream.is_big_endian()) {
        return be32toh(bytes);  // 大端转主机序
    } else {
        return le32toh(bytes);  // 小端转主机序
    }
}

对齐规则

CDR 要求数据按类型自然边界对齐:

数据类型 对齐要求
char 1 字节
short 2 字节
long/float 4 字节
double 8 字节
string/sequence 4 字节(长度域)

示例
序列化 short + long 时:

short s = 0x1234;
long  l = 0x56789ABC;

内存布局(小端序 + 2 字节填充):

| s (2B) | 填充 (2B) | l (4B)       |
|--------|-----------|--------------|
| 34 12  | 00 00     | BC 9A 78 56  |

CDR 使用场景

  1. CORBA 远程调用
    • 参数传递和返回值序列化
  2. DDS(Data Distribution Service)
    • 实时系统中的数据发布/订阅
  3. 金融交易系统
    • 交易所间的低延迟数据交换
  4. 航空电子系统
    • ARINC 653 标准中的进程间通信

CDR 优缺点

优点 缺点
零解析开销(直接内存映射) 无自描述性(需 IDL 定义)
自动处理跨平台差异 不支持动态模式演化
支持复杂类型(联合体、序列) 二进制格式难以人工调试

💡 替代方案对比

  • Protocol Buffers:自描述、支持版本演化,但需要运行时解析
  • JSON/XML:可读性好,但序列化开销大

实战示例(C++ 使用 ACE_CDR)

#include <ace/CDR_Stream.h>

// 序列化
Person person{4487, "Alice"};
ACE_OutputCDR output;
output << person.id << person.name;
ACE_Message_Block* mb = output.begin();  // 获取CDR字节流

// 反序列化
ACE_InputCDR input(mb);
long id;
ACE_CDR::Char* name;
input >> id >> name;  // 自动处理字节序

通过 CDR 的标准化序列化机制,CORBA 实现了真正的跨平台对象通信,成为分布式系统的基石技术之一。

示例

下面是一个详细的小端序 CDR(Common Data Representation)序列化示例,展示如何在小端序系统上序列化和反序列化数据。我们将使用一个包含多种数据类型的结构体进行演示。


示例结构体定义(IDL)

struct SensorData {
    unsigned short sensorId;  // 2 字节
    float temperature;       // 4 字节
    string location;         // 变长字符串
};

要序列化的数据:

  • sensorId = 0x1234(十进制 4660)
  • temperature = 25.5(浮点数)
  • location = "Lab"(字符串)

步骤 1:小端序 CDR 序列化

在小端序系统中(如 x86 CPU),数据低位字节存储在低地址:

序列化流程
  1. 字节序标志:写入 0x01(表示小端序)
  2. sensorId (2 字节)
    • 原始值:0x1234
    • 小端序:0x340x12
  3. 填充字节:因下个字段是 4 字节 float,需 2 字节填充
  4. temperature (4 字节)
    • 25.5 的 IEEE 754 表示:0x41CC0000
    • 小端序:0x000x000xCC0x41
  5. location 字符串
    • 长度(4 字节):"Lab" = 3 字符 + 1 终止符 → 长度=4 → 0x04000000(小端序)
    • 内容:L(0x4C), a(0x61), b(0x62), \0(0x00)
    • 填充:4 字节内容后无需填充(已是 4 字节对齐)
完整字节流(低地址 → 高地址):
| 字段        | 值 (十六进制)                 | 说明                     |
|-------------|-------------------------------|--------------------------|
| 字节序标志  | 01                            | 小端序标识               |
| sensorId    | 34 12                         | 低位在前                 |
| 填充        | 00 00                         | 对齐下一个4字节字段      |
| temperature | 00 00 CC 41                   | 浮点数字节逆序           |
| 字符串长度  | 04 00 00 00                   | 长度=4 (小端序)          |
| 字符串内容  | 4C 61 62 00                   | "Lab\0"                 |

可视化内存布局

低地址 → 高地址
01 34 12 00 00 00 00 CC 41 04 00 00 00 4C 61 62 00

步骤 2:小端序 CDR 反序列化

当接收方(小端序系统)读取此字节流时:

  1. 读字节序标志0x01 → 确认小端序
  2. 读 sensorId
    • 取 2 字节:0x34 0x12
    • 按小端序解析:0x1234 = 4660
  3. 跳过填充:忽略 2 字节 0x00 0x00
  4. 读 temperature
    • 取 4 字节:0x00 0x00 0xCC 0x41
    • 按小端序重组:0x41CC0000 → 25.5
  5. 读字符串
    • 读长度(4 字节):0x04 0x00 0x00 0x00 → 小端序 = 4
    • 读 4 字节内容:0x4C 0x61 0x62 0x00 → “Lab”

关键机制解析

1. 字节序自动处理
// 伪代码:小端序序列化float
void serialize_float(float value, CDRStream& stream) {
    uint32_t intRep = *(uint32_t*)&value; // 二进制表示
    if (stream.is_little_endian()) {
        write_bytes(intRep); // 直接写入(小端系统)
    } else {
        write_bytes(swap_bytes(intRep)); // 大端需转换
    }
}
2. 对齐填充规则
偏移 字段 大小 对齐要求 操作
0 字节序标志 1 - 写入 0x01
1 sensorId 2 2 直接写入
3 <填充> 2 4 填充 0x0000
5 temperature 4 4 写入浮点
9 字符串长度 4 4 直接写入
13 字符串内容 4 1 写入+无填充
3. 字符串处理
// 字符串序列化伪代码
void serialize_string(string s, CDRStream& stream) {
    uint32_t len = s.length() + 1; // 包含 \0
    serialize_uint32(len);         // 写长度(小端序)
    write_bytes(s.c_str(), len);   // 写原始字符
    
    // 4字节对齐填充 (字符数据无额外填充)
}

小端序 vs 大端序 CDR 对比

同一数据 SensorData{4660, 25.5, "Lab"} 的差异:

字节序 CDR 字节流(十六进制)
小端序 01 34 12 00 00 00 00 CC 41 04 00 00 00 4C 61 62 00
大端序 00 12 34 00 00 41 CC 00 00 00 00 00 04 4C 61 62 00

差异说明:

  1. 字节序标志不同(0x01 vs 0x00
  2. 数值字段字节逆序:
    • sensorId: 34 12 vs 12 34
    • temperature: 00 00 CC 41 vs 41 CC 00 00
  3. 长度字段:04 00 00 00 vs 00 00 00 04

实际应用场景

  1. 嵌入式系统通信(ARM Cortex-M 小端设备)

    // 发送端(小端系统)
    SensorData data = {0x1234, 25.5, "Lab"};
    CDR_serialize(&output_stream, data); // 直接内存拷贝
    
    // 接收端(同为小端系统)
    CDR_deserialize(&input_stream, &data); // 零转换开销
    
  2. 混合字节序环境(需显式转换)

    // 接收方是大端系统(如 PowerPC)
    CDRStream stream = receive_network_data();
    if (stream.endian_flag == 0x01) { // 检测到小端数据
        convert_cdr_to_host_order(&stream); // 字节序转换
    }
    deserialize(&stream, &data);
    

重要注意事项

  1. 字节序标志位置:始终是 CDR 流的第一个字节
  2. 嵌套结构处理:内部结构不添加额外字节序标志
  3. 浮点数兼容性:所有平台必须使用 IEEE 754 标准
  4. 数据对齐:即使在同字节序系统中,填充仍不可省略
  5. 性能优势:小端系统处理小端 CDR 时,可直接内存映射(零拷贝)

通过这个示例,您可以看到 CDR 如何在小端序系统中高效地处理数据序列化,同时保持跨平台兼容性。核心在于字节序标志和对齐规则的应用,使得不同架构的设备能正确解析数据。


网站公告

今日签到

点亮在社区的每一天
去签到