事件Schema与二进制编码练习
前置:能阅读字段编号、整数位操作和 UTF-8 字节长度;Python 3.10+ 用于有限 wire 编码器,区别手写模型与生成代码。教学范围为proto3显式optional;二进制wire;Python3.10+手写有限编码器。核对日期2026-10-17。示例未执行,本轮没有安装依赖、生成协议代码、启动服务或浏览器预览。完整源码和输入文件见下方「同源完整文件」;推演结论只适用于写明的模型。
完整事件schema与编码
完整事件schema与编码用event_id字段1和title标题字段2构造二进制事件,optional note字段3展示未来扩展。手写程序只编码前两字段并跳过支持类型的未知字段,用于看清字节而非替代官方运行库;schema与源码均完整展示。
事件字节预期
事件字节预期在event_id=150、title=A时为十六进制089601120141:08是字段1标签,9601是150的变长编码,12是字段2标签,01是一个字节长度,41是A。长度指字节而非字符,“你”的长度为3。
变长整数逐步练习
变长整数逐步练习拆解300:低七位44,剩余2,因此第一个字节置继续位成为172即ac,第二个字节02。加上字段1标签08得到08ac02;字符串长度如果超过127也需使用变长编码,不能固定写一个长度字节。
同源完整文件
以下README含前置、输入、读者自跑步骤、预期结果、失败、恢复与清理;只做静态核对,没有执行。
event.proto
syntax = "proto3";
package events.v1;
message Event {
uint32 event_id = 1;
string title = 2;
optional string note = 3;
reserved 4, 5;
reserved "old_type";
}wire.py
import json
import sys
def varint(value):
if type(value) is not int or not 0 <= value <= 0xffffffff:
raise ValueError('uint32 required')
output = bytearray()
while value > 127:
output.append((value & 127) | 128)
value >>= 7
output.append(value)
return bytes(output)
def read_varint(data, position):
value = 0
for shift in range(0, 35, 7):
if position >= len(data):
raise ValueError('truncated varint')
byte = data[position]
position += 1
value |= (byte & 127) << shift
if byte < 128:
if value > 0xffffffff:
raise ValueError('uint32 overflow')
return value, position
raise ValueError('varint too long')
def encode(identifier, title):
if not isinstance(title, str):
raise ValueError('title string required')
content = title.encode('utf-8')
if len(content) > 1024:
raise ValueError('title too large')
return b'\x08' + varint(identifier) + b'\x12' + varint(len(content)) + content
def decode(data):
if len(data) > 4096:
raise ValueError('message too large')
result, position = {'event_id': 0, 'title': ''}, 0
while position < len(data):
tag, position = read_varint(data, position)
field, wire = tag >> 3, tag & 7
if field == 0:
raise ValueError('invalid field zero')
if field in (1, 2) and wire != {1: 0, 2: 2}[field]:
raise ValueError('unexpected known-field wire type')
if wire == 0:
value, position = read_varint(data, position)
elif wire == 2:
length, position = read_varint(data, position)
if position + length > len(data):
raise ValueError('truncated payload')
value = data[position:position + length]
position += length
else:
raise ValueError('unsupported wire type')
if field == 1:
result['event_id'] = value
elif field == 2:
result['title'] = value.decode('utf-8')
return result
if __name__ == '__main__':
try:
request = json.load(sys.stdin)
data = bytes.fromhex(request['hex']) if 'hex' in request else encode(request['event_id'], request['title'])
print(json.dumps({'hex': data.hex(), 'decoded': decode(data)}, ensure_ascii=False))
except (ValueError, TypeError, KeyError) as error:
print(str(error), file=sys.stderr)
sys.exit(2)requirements.txt
# Python 3.10+ standard library only; no third-party dependency.README.md
# Protocol Buffers数据契约:完整示例
示例未执行。核对日期2026-10-17。教学版本族:proto3显式optional;二进制wire;Python3.10+手写有限编码器。
## 文件与依赖
文件:event.proto, wire.py, requirements.txt。requirements.txt为同源依赖声明;所有代码和配置都随本文展示。wire.py 仅用 Python 3.10+ 标准库;event.proto 是契约对照文件,本轮没有生成代码。
## 输入与前置
前置:理解字段标签、varint、长度前缀和 UTF-8 字节。使用 Python 3.10+ 标准库运行手写 wire.py,不依赖 gRPC 或生成的消息类;event.proto 用于对照契约。输入为编码或解码请求,字段值、字节与错误预期见下节。
读者将来自跑(本轮未执行):在本目录以Python 3.10+读取input.json,PowerShell示意`Get-Content -Raw input.json | python wire.py`;Bash示意`python3 wire.py < input.json`。把下面输入手工保存为UTF-8文件,输出按预期逐项比较。无需安装依赖,没有服务或网络调用;程序只读标准输入并写标准输出,不改原文件。失败信息写标准错误且退出2。恢复是修正输入后重读,清理只删除自己创建的input.json与输出文件,勿递归删除工作目录。
## 预期结果、失败与恢复
event_id=150,title=A对应089601120141;解码同样返回两字段。08ac02对应event_id=300。截断的0896必须拒绝;未知wire类型如0d必须拒绝,而不是假装能完整透传。
失败要保留输入和错误,先与正文的不变量及边界核对。没有真实服务或性能验证,不以这些模型输出证明生产可用性。
## 独立练习
手算ID300、标题“你”的字节,并说明新增optional note对本课解码器有什么影响。
参考答案:ID字段08ac02;标题字段12、长度03、UTF-8e4bda0,因此整体08ac021203e4bda0。note标签1a属于wire2,可按长度跳过;本工具丢弃未知内容,所以不能当无损代理,官方消息对象的未知字段保留策略仍需核对。先作答,再核对
手算ID300、标题“你”的字节,并说明新增optional note对本课解码器有什么影响。
逐步参考解答
ID字段08ac02;标题字段12、长度03、UTF-8e4bda0,因此整体08ac021203e4bda0。note标签1a属于wire2,可按长度跳过;本工具丢弃未知内容,所以不能当无损代理,官方消息对象的未知字段保留策略仍需核对。
按字节核对事件
同一个示例可以从schema、标签和值三个方向核对。150的低7位是22,继续位使首字节为96;剩余1写为01。标题A的UTF-8长度为1,所以字段2由12、01、41组成。图中按十六进制展示,这不是要求所有消息字段都按固定顺序序列化。
查看图表代码
来源与适用边界
- 英文官方、作者或规范原文:本专题机制依据;按上述固定版本族阅读。
- 中文官方或作者资料:用于术语和讲解交叉核对,冲突以原始规范为准。
- 官方wire编码:标签、变长整数与长度分隔,不承诺规范唯一字节表示。
继续阅读
- 消息与线上表示