potocol Buffers (简称 protobuf) 是 Google 开发的一种高效的数据序列化格式,用于结构化数据的序列化、反序列化和传输。以下是 protobuf 的全面解析:
核心特性
- 跨语言支持:支持 C++, Java, Python, Go, C#, Ruby 等多种语言
- 高效二进制格式:比 XML/JSON 更小、更快
- 强类型接口:通过
.proto
文件定义数据结构 - 向后兼容:支持字段扩展而不破坏旧代码
- 代码生成:通过编译器生成数据访问类
字段规则
singular
: 单数字段(proto3默认)repeated
: 数组/列表字段map<K,V>
: 映射表字段(proto3特有)oneof
: 互斥字段组(同一时间只能设置其中一个)- optional: 可选
- required: 表示必须赋值,否则序列化会失败(proto3 已移除此修饰符,需确保调用方赋值)。-》在 proto3 中,所有字段默认为
optional
,建议通过业务逻辑强制校验必填字段,而非依赖协议 - 在 Protocol Buffers 的 C++ API 中,
repeated
字段通常提供以下方法:如下为消息定义: des_relation_size()
→ 获取列表大小(类似std::vector::size()
)。des_relation(i)
→ 获取第i
个元素(索引从0
开始)。add_des_relation()
→ 添加一个新元素(返回可修改的引用)。
成员变量访问语法
1、修改:set_<field_name>()
3、成员是否存在:has_<field_name>()
4、获取 repeated/map 字段长度
5、检查字符串字段是否为空.empty()
session_info.audio_media_info().peer_key().empty()
安全注意事项
- 无需检查嵌套消息是否存在
- 即使
audio_media_info
未设置,audio_media_info()
也会返回有效(但空)的默认消息,不会引发空指针异常。 - 直接调用
peer_key().empty()
是安全的。
- 即使
- 与
has_...()
的区别- 如果需要区分"字段未设置"和"显式设置为空",需使用
has_audio_media_info()
(仅 proto2 或 proto3 的optional
字段支持):
- 如果需要区分"字段未设置"和"显式设置为空",需使用
bool is_explicitly_empty = session_info.has_audio_media_info() && session_info.audio_media_info().peer_key().empty();
6、获取字符串字段长度 .size()
size_t key_length = session_info.audio_media_info().peer_key().size();
- 与
empty()
的关系peer_key().size() == 0
等价于peer_key().empty()
,但语义更明确(显式检查长度)。
7、获取字符串字段的底层字符数组(C 风格字符串).data()
const char* key_data = session_info.audio_media_info().peer_key().data();
data()
调用 std::string::data()
,返回指向字符串内容的 const char*
(C 风格字符串)。
C++11 起:保证以 \0
结尾(等同于 c_str()
)。
C++11 前:不一定以 \0
结尾,需结合 size()
使用。
8、默认值处理
proto3 中未设置的字段会返回类型默认值:
数字类型:0
布尔类型:false
字符串:空字符串 ""
嵌套消息:null(语言相关)
9、数据类型
10、关键注意事项
- proto2 vs proto3
- has 方法在 proto3 中仅对 optional 或消息字段有效。
- 性能优化
- 对 repeated 字段预分配空间(C++):
msg.mutable_des_media_session_id()->Reserve(100);
- 线程安全
- Protobuf 对象非线程安全,修改时需加锁。
11、版本差异: proto2 vs proto3
使用流程
- 编写 .proto 文件定义数据结构
- 使用 protoc 编译器生成代码:
protoc --cpp_out=. example.proto
protoc --java_out=. example.proto
3、在代码中使用生成的类: