Protocol——协议数据结构有什么

Protocol 回答的问题是:「收发的字节长什么样?」 它被逼出来的原因是「裸字节没法用,每个调用者都要自己猜」。这一篇讲它有什么。关键结论:Protocol 是数据结构,不是组件——它是「消息长什么样」的一份定义。


一、它解决什么问题

网络收发的是原始字节

1
收到:0x00 0x00 0x00 0x10 0x00 0x00 0x00 0x02 ...

调用者需要知道「这 4 字节是长度、接下来 4 字节是命令、后面是数据」——每个调用者都要自己猜、自己定义。版本一改,所有地方都要跟着改。

Protocol 被逼出来的原因:把「消息长什么样」的定义统一起来,只写一份。


二、它有什么(就是一份 struct 定义)

Protocol 的全部内容,就是一个数据结构:

1
2
3
4
5
struct Message {
uint32_t length; // 消息长度
uint32_t command; // 命令类型
uint8_t payload[];// 消息体
};
1
它有什么:只有「定义」,没有「算法」,没有「接口」,没有「生命周期」

这就是为什么 Protocol 不是组件

1
2
3
4
5
6
组件 = 数据结构 + 算法 + 接口(有行为,能被调用)
Protocol = 只有数据结构(没有算法,没有接口,不能被调用)

EventLoop 有 run() 能被调用 → 组件
Buffer 有 append() 能被调用 → 组件
Protocol 只是 struct Message → 不是组件,是定义

三、它的边界:只管「定义」,不做「转换」

1
2
✅ 管:消息长什么样(格式、字段、版本)
❌ 不管:字节 ↔ 消息的转换(那是入口系统解析层的事)
1
2
3
4
5
6
7
Protocol(协议定义,网络系统):
struct Message { length, command, payload };
回答「消息长什么样」

Parser(解析层,入口系统):
Message parse_request(const uint8_t* bytes, size_t len);
回答「怎么从字节变出消息」

这是最容易混的一对

1
2
协议   = 定义(数据结构,属于网络系统)
解析 = 转换(可运行逻辑,属于入口系统)

Protocol 定义「消息有几个字段、各占几字节」;Parser 拿着这份定义,把一堆字节切出来填进结构体。


四、协议格式 vs 协议状态

Protocol 里还有一个容易混的点——「协议格式」和「协议状态」:

1
2
3
4
5
6
7
协议格式(Protocol,数据结构):
→ 消息长什么样,是「死的」
→ struct Message

协议状态(属于 Session,不是 Protocol):
→ 握手、正常、关闭,是「活的」
→ Session.state = HANDSHAKING / NORMAL / CLOSING
1
2
格式是死的定义(几字段、几字节)
状态是活的流转(这个会话走到哪一步)

所以「协议版本不匹配」「握手失败」这类异常,不属于 Protocol(数据结构),而属于 Session(状态)


五、它的形态:数据结构,不需要封装

1
2
3
有状态组件(EventLoop 等)→ 类封装
无状态工具(Buffer) → 函数导出
数据结构(Protocol) → 不需要封装,被直接引用

Protocol 就是一份 struct Message 定义,放在 protocol.h 里:

1
2
3
4
5
6
// protocol.h —— 只有定义,没有函数、没有类
struct Message {
uint32_t length;
uint32_t command;
uint8_t payload[];
};

谁要用,谁 #include "protocol.h" 直接引用这份定义。它不「运行」,所以不需要封装、不需要生命周期。


六、它的异常:没有

1
2
3
4
Protocol 本身没有异常——它是死的定义。

「协议版本不匹配」→ Session 的异常(握手失败)
「消息格式错误」 → 入口系统解析层的异常

一个 struct 定义不会「出错」。会出错的是「拿着这份定义去做转换/校验」的代码——那些代码分别在解析层和 Session 里。


七、它和其他组件的关系

1
2
3
4
5
Protocol ← 被 Session 引用(ProtocolState 字段)
Protocol ← 被 Connection 引用(知道消息长什么样)
Protocol ← 被入口系统解析层引用(按定义做字节↔消息转换)

方向是单向的:所有人引用 Protocol,Protocol 不依赖任何人
1
2
3
    ┌─────────────── Protocol(struct Message 定义)───────────────┐
↓ ↓ ↓
Session.state Connection(收发) 入口系统 Parser(转换)

Protocol 是被所有人引用的「公共定义」,它本身是最底层、最被动的东西。


八、小结

1
2
3
4
5
6
7
8
9
10
11
12
Protocol 有什么:
职责:消息长什么样(格式、字段、版本)
结构:就是 struct Message 定义
边界:只管「定义」,不管「转换」(解析层的事)
形态:数据结构,不需要封装
异常:没有(死的定义不会出错)

关键:
协议 ≠ 解析(定义 vs 转换)
协议格式 ≠ 协议状态(死定义 vs 活状态)

一句话:Protocol 是「消息长什么样」的一份数据结构定义,不是组件。