菜单

消息处理系统

相关源文件

本文档提供了 Protocol Buffer 消息在 protobuf 库中如何处理的技术概述。它涵盖了协议缓冲区消息的解析、序列化、访问和操作的核心机制。本文档侧重于消息的运行时处理,而不是代码生成过程(该过程已单独介绍)。

概述

消息处理系统负责

  1. 将序列化的 Protocol Buffer 解析为消息对象
  2. 将消息对象序列化回二进制格式
  3. 通过直接 API 和反射提供字段访问
  4. 管理特殊字段类型,如 map 和 oneof
  5. 通过 arena 分配管理内存

来源:src/google/protobuf/message.h244-412 src/google/protobuf/message_lite.h502-672 src/google/protobuf/message.cc65-101

消息类层次结构

消息处理系统围绕两个主要接口构建

  1. MessageLite:轻量级接口,提供基本操作,不包含反射支持
  2. Message:扩展了 MessageLite,增加了反射和动态访问功能

来源:src/google/protobuf/message_lite.h502-672 src/google/protobuf/message.h244-412 src/google/protobuf/dynamic_message.cc13-167

消息解析系统

解析系统将序列化的 Protocol Buffer 数据转换为内存中的消息对象。

解析架构

Protocol Buffers 采用表驱动的解析方法以实现最佳性能

来源:src/google/protobuf/parse_context.h65-93 src/google/protobuf/generated_message_tctable_lite.cc194-198 src/google/protobuf/message_lite.cc101-104

解析过程

  1. 解析器从输入流中读取一个标签(字段编号和线类型)
  2. 它使用解析表查找字段描述符
  3. 根据字段类型,它会调用适当的处理程序来解析字段值
  4. 解析后的值存储在消息对象中
  5. 此过程一直持续到到达输入末尾或达到限制

表驱动解析

解析使用在编译时生成的表来优化字段查找和处理

来源:src/google/protobuf/generated_message_tctable_lite.cc194-341 src/google/protobuf/compiler/cpp/parse_function_generator.cc149-195

字段类型和存储

Protocol Buffers 支持各种字段类型,每种类型在解析和序列化期间都有特定的处理方式。

字段布局

每个字段的存储由其类型、基数(singular/repeated)和其他属性决定

来源:src/google/protobuf/generated_message_tctable_impl.h74-270 src/google/protobuf/generated_message_reflection.cc416-533

字段基数

字段可以具有影响其存储和处理的各种基数

基数描述存储类型
Singular(单数)具有 0 或 1 个值的字段直接值存储
可选具有可选存在性的字段直接值 + has 位
Repeated(复数)具有 0 个或多个值的字段RepeatedField/RepeatedPtrField
Oneof(联合)互斥字段联合存储 + case 枚举

来源:src/google/protobuf/generated_message_tctable_impl.h108-117

Map 字段处理

Map 字段需要特殊处理,因为它们代表键值集合。

Map 实现

Map 使用哈希表实现,具有专门的编码/解码过程

来源:src/google/protobuf/map.h57-547 src/google/protobuf/map_field.h1-64 src/google/protobuf/dynamic_message.cc89-163

Map 处理流程

Map 在解析和序列化期间通过专门的流程进行处理

来源:src/google/protobuf/map.h250-451 src/google/protobuf/map_field.h1-64

反射系统

反射系统支持消息字段的运行时检查和操作。

反射架构

来源:src/google/protobuf/message.h369-375 src/google/protobuf/generated_message_reflection.h15-67 src/google/protobuf/generated_message_reflection.cc343-546

反射流程

反射系统允许对消息字段进行通用访问

来源: src/google/protobuf/message.h426-527 src/google/protobuf/message.cc92-101

序列化系统

序列化过程将内存中的消息对象转换回序列化的二进制格式。

序列化架构

来源: src/google/protobuf/message_lite.cc105-127 src/google/protobuf/message.cc79-90

线格式编码

消息使用标签-长度-值(tag-length-value)的方法进行序列化

字段组件描述
标签字段编号和线类型(varint 编码)
线类型编码类型(varint、fixed32、fixed64、length-delimited)
字段值根据线类型进行编码

来源: src/google/protobuf/generated_message_reflection.cc543-603

内存管理

Protocol Buffers 库使用 Arena 分配来优化消息的内存管理。

Arena 分配

来源: src/google/protobuf/message_lite.h56-78 src/google/protobuf/message_lite.cc53-75

结论

Protocol Buffers 消息处理系统为处理结构化数据提供了一个强大的框架。它通过以下方式平衡了性能和灵活性:

  1. 通过表驱动方法实现高效的解析和序列化
  2. 通过生成代码和反射提供灵活的访问
  3. 支持地图和消息等复杂类型
  4. 通过 Arena 分配实现优化的内存管理

该系统构成了 Protocol Buffers 的核心运行时,通过紧凑的线格式实现了高性能的跨语言数据互换。