消息层设计:消息头/体/尾结构、标准字段字典、自定义扩展字段
消息层,说白了就是交易接口的「通用语言」。
我做了这么多年跨市场对接,见过最头疼的事就是:A交易所的消息体里塞了个时间戳,B交易所却把它放在消息头里。解析起来简直要命。所以消息层的标准化,核心就是三件事——头、体、尾怎么切,字段怎么定,扩展怎么留。
一、消息头:谁发的、发给谁、多长、啥时候
消息头是每次通信的「快递面单」。我个人习惯,头里只放四个核心字段:
| 字段名 | 类型 | 长度(字节) | 说明 |
|---|---|---|---|
| MsgType | uint16 | 2 | 消息类型编码,比如 0x0001 表示下单 |
| BodyLength | uint32 | 4 | 消息体长度,不含头和尾 |
| SequenceNo | uint64 | 8 | 序列号,用于去重和排序 |
| Timestamp | uint64 | 8 | Unix毫秒时间戳 |
嗯,这里要注意:消息头总长度必须固定。我见过有人把可变长字段塞进消息头,结果解析器写得跟迷宫一样。固定长度,22字节,谁解析都不费劲。
避坑指南:我曾经在对接某海外交易所时,对方消息头里塞了个「预留字段」,长度还不固定。后来每次版本升级,那个预留字段就变一次含义。从那以后,我定死一条规矩——消息头里不准有预留字段,所有扩展走消息尾。
二、消息体:业务数据的「集装箱」
消息体就是实际业务数据。我建议用TLV(Type-Length-Value)结构来组织。为什么?因为灵活。
// 消息体通用结构
struct MsgBody {
uint16 fieldCount; // 字段数量
Field fields[]; // 字段列表
};
struct Field {
uint16 fieldType; // 字段类型编码
uint16 fieldLength; // 字段值长度
byte value[]; // 字段值
};
你想想看,如果每个字段都固定位置,那加一个新字段就得改整个协议。用TLV,解析器只需要按类型处理,不认识的就跳过。我在项目中就用这套方案对接过6个交易所,消息体定义只改过一次——加了个「算法标识」字段。
三、消息尾:校验与扩展的「安全锁」
消息尾很多人会忽略,其实它很重要。我一般放两个东西:
- CRC32校验:4字节,对整个消息(头+体)做校验。别用简单的累加和,容易被绕过。
- 扩展字段区:也是TLV结构,但只放「非标准」的东西。比如某个交易所特有的「交易员备注」。
小技巧:扩展字段区的Type编码从0xF000开始,跟标准字段区分开。这样解析器一看Type值,就知道是标准字段还是扩展字段,不用查表。
四、标准字段字典:大家都能看懂的数据字典
标准字段字典,就是给每个字段一个全球唯一的编号。我参与设计过一套字典,核心原则就两条:
- 按业务域分组:0x0001-0x0FFF是订单域,0x1000-0x1FFF是行情域,0x2000-0x2FFF是账户域。这样一看编码就知道是干啥的。
- 预留足够空间:每个域留80%的空编码。别抠抠搜搜的,万一以后要加字段呢?
| 编码范围 | 业务域 | 示例字段 |
|---|---|---|
| 0x0001 - 0x0FFF | 订单 | 0x0001 订单ID, 0x0002 价格, 0x0003 数量 |
| 0x1000 - 0x1FFF | 行情 | 0x1001 最新价, 0x1002 买一价, 0x1003 卖一价 |
| 0x2000 - 0x2FFF | 账户 | 0x2001 账户ID, 0x2002 可用余额, 0x2003 冻结余额 |
五、自定义扩展字段:给「特殊需求」留的后门
标准化永远覆盖不了所有场景。比如某个交易所要求传「交易员IP地址」,标准字典里没有。怎么办?用扩展字段。
我设计的扩展字段规则很简单:
- 编码从0xF001开始,跟标准字段不冲突。
- 扩展字段必须带「域标识」:前2字节是交易所代码,后2字节是自定义编码。比如0xF001 + 0x0001(上交所)+ 0x0001(IP地址)。这样不同交易所的扩展字段不会撞车。
- 解析器遇到不认识扩展字段直接跳过,不影响主流程。
注意:扩展字段不能用于核心业务逻辑。比如「订单价格」这种核心字段,必须用标准字段。扩展字段只放「辅助信息」。我曾经见过有人把「订单类型」塞进扩展字段,结果两个交易所的解析器理解不一样,直接导致错单。血的教训。
六、整体消息结构图
下面这张图,把消息头、体、尾的关系画清楚了。你看一眼就明白。
你看,整个消息就像一列火车:车头(消息头)固定尺寸,车厢(消息体)装货物,车尾(消息尾)做检查和挂额外包裹。每节车厢都按TLV打包,想加就加,想减就减。
核心原则:消息头固定、消息体TLV、消息尾校验+扩展。这三层各司其职,互不干扰。我在设计跨市场接口时,只要守住这个结构,后面加再多交易所都不慌。
说白了,消息层设计就是「定规矩」。规矩定好了,大家按规矩来,对接效率能提升好几倍。你想想看,如果每个交易所都自己搞一套消息结构,那量化系统光解析消息就得写几十个版本——这种事我干过,真的累。
个人经验:我建议你在设计消息层时,先画一张类似上面的结构图,给团队所有人看。大家达成共识了再写代码。我曾经因为没画图,跟同事争论「扩展字段放头里还是尾里」吵了三天。后来图一画,三分钟就定了。
公众号:蓝海资料掘金营,微信deep3321