Protocol Buffers 概述
简介
Protocol Buffers语言无关,平台无关,可扩展的结构化数据序列化方案, 用于协议通讯, 数据存储和其他更多用途。是一个灵活,高效,自动化的结构化数据序列化机制。
原理
在.proto文件中定义protocol buffer消息类型来指定要序列化的信息如何组织。
protocol buffer信息是一个小的信息逻辑记录,包含一序列的”名字-值”对。
1 | message Person { |
每个消息类型有一个或者多个唯一的编号的字段,而每个字段有一个名字和值类型。
在.proto文件上运行对应应用语言的protcol buffer的编译器来生成数据访问类。
这些类为每个字段(类似name()或者set_name())提供简单的访问器,还有用于序列化/解析整个结构到/从原始字节的方法。
安装使用
安装
下载通用编译器
地址:https://github.com/protocolbuffers/protobuf/releases
Protobuf 运行时安装
grpc官网安装
1 | $ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 |
使用
- 编写.proto文件
- 使用protoc工具生成代码文件
- 调用
1 | syntax = "proto3"; |
1 | protoc --go_out=. --go-grpc_out=. helloworld/helloworld.proto |
- –go_out .pd.go文件生成目录
- –go-grpc_out _grpc.pd.go文件生成目录
1 | package main |
定义消息类型
定义消息类型.proto
文件
1 | syntax = "proto3"; |
为消息定义中的每个字段指定一个介于1
和#之间的数字,给定的数字在该消息的所有字段中必须是唯一的。
字段规则
required
:消息体中必填字段,不设置会导致编解码异常。默认使用。optional
: 消息体中可选字段。生成指针类型。repeated
: 消息体中可重复字段,重复的值的顺序会被保留(例如位置3)在go中重复的会被定义为切片。
1 | message User { |
定义多种消息类型
1 | message SearchRequest { |
添加注释
1 | /* SearchRequest represents a search query, with pagination options to |
对于Go,编译器生成一个.pb.go
文件,每个文件都有一个类型消息类型。
值类型
.proto Type | GO Type |
---|---|
double | float64 |
float | float32 |
int32 | Int32 |
uint32 | uint32 |
int64 | long |
bool | bool |
string | string |
bytes | []byte |
默认值
被编码的消息没有包含特定的简单元素, 被解析的对象对应的字段被设置为默认值。
- 对于strings, 默认值是空字符串(注, 是””, 而不是null)
- 对于bytes, 默认值是空字节(注, 应该是byte[0], 注意这里也不是null)
- 对于boolean, 默认值是false.
- 对于数字类型, 默认值是0.
- 对于枚举, 默认值是第一个定义的枚举值, 而这个值必须是0.
- 对于消息字段, 默认值是null.
枚举
能希望某个字段只能有预先定义的多个值中的一个。
1 | message SearchRequest { |
Corpus 枚举的第一个常量设置到0: 每个枚举定义必须包含一个映射到0的常量作为它的第一个元素.
- 必须有一个0值, 这样我们才能用0来作为数值默认值.
- 0值必须是第一个元素
消息调用
可以使用其他消息类型作为字段类型。
1 | message SearchResponse { |
导入定义
消息类型已经在其他的.proto文件中定义。
导入来使用来自其他.proto文件的定义. 为了导入其他.proto的定义, 需要在文件的顶端增加导入声明:
1 import "myproject/other_protos.proto";
需要移动.proto文件到新的位置。
在原有位置放置一个伪装的.proto文件, 通过使用import public方式转发所有的import到新的位置。其他任何导入这个包含import public语句的proto文件都可以透明的得到通过import public方法导入的依赖。
protocol编译器在通过命令行-I/–proto_path参数指定的目录集合中搜索导入的文件。如果没有指定, 则在编译器被调用的目录下查找. 通常应该设置–proto_path参数到项目所在的根目录然后为所有的导入使用完整限定名。
消息嵌套
可以在消息类型内部定义和使用消息类型。
1 | message SearchResponse { |
在父消息类型之外重用消息类型。
1 | message SomeOtherMessage { |
定义服务
在.proto文件中定义RPC服务接口, 然后protocol buffer编译器会生成所选语言的服务接口代码和桩(stubs)。
定义一个RPC服务,带一个方法处理SearchRequest并返回SearchResponse。
1 | service SearchService { |
生成类
- 定义在.proto文件中的消息类型
- 在.proto文件上运行protocol buffer编译器protoc
- 对于Go, 需要为编译器安装特别的代码生成插件
选项参数
- –proto_path=:指定一个目录用于查找.proto文件, 当解析导入命令时. 缺省使用当前目录。
- –go_out=:生成代码文件的目录。
1 | protoc --proto_path=IMPORT_PATH --go_out=DST_DIR |