Protobuf语法
Protobuf是Protocol Buffer的简称,它是Google公司开发的一种数据描述语言,用于描述一种轻便高效的结构化数据存储格式,是一种高效的数据格式,平台无关、语言无关、可扩展,常用于RPC系统和持续数据存储系统。
字段规则
字段格式
限定修饰符 | 数据类型 | 字段名称 | = | 字段编码值 | [字段默认值]
限定修饰符
required、optional、repeated
- Required:表示是一个必须字段
- Optional:表示一个可选字段。对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段
- Repeated:表示该字段可以包含0-N个元素。其中特性和optional一样,但是每一次可以包含多个值。可以看做是在传递一个数组的值
数据类型
Protobuf定义了一套基本数据类型:
.proto 类型 | Notes | C++ Type | Java Type | Python Type | Go Type | Ruby Type | C# Type | PHP Type | Dart Type |
---|---|---|---|---|---|---|---|---|---|
double | double | double | float | float64 | Float | double | float | double | |
float | float | float | float | float32 | Float | float | float | double | |
int32 | 使用可变长度编码。编码负数的效率低 - 如果您的字段可能有负值,请改用sint32。 | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
int64 | 使用可变长度编码。编码负数的效率低 - 如果您的字段可能有负值,请改用sint64。 | int64 | long | int/long[] | int64 | Bignum | long | integer/string[] | Int64 |
uint32 | 使用可变长度编码 | uint32 | int | int/long | uint32 | Fixnum or Bignum (as required) | uint | integer | int |
uint64 | 使用可变长度编码. | uint64 | long | int/long | uint64 | Bignum | ulong | integer/string[] | Int64 |
sint32 | 使用可变长度编码。签名的int值。这些比常规int32更有效地编码负数。 | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
sint64 | 使用可变长度编码。签名的int值。这些比常规int64更有效地编码负数。 | int64 | long | int/long | int64 | Bignum | long | integer/string[] | Int64 |
fixed32 | 总是四个字节。如果值通常大于228,则比uint32更有效。 | uint32 | int | int/long | uint32 | Fixnum or Bignum (as required) | uint | integer | int |
fixed64 | 总是八个字节。如果值通常大于256,则比uint64更有效 | uint64 | long | int/long[] | uint64 | Bignum | ulong | integer/string[] | Int64 |
sfixed32 | 总是四个字节 | int32 | int | int | int32 | Fixnum or Bignum (as required) | int | integer | int |
sfixed64 | 总是八个字节 | int64 | long | int/long | int64 | Bignum | long | integer/string[] | Int64 |
bool | bool | boolean | bool | bool | TrueClass/FalseClass | bool | boolean | bool | |
string | 字符串必须始终包含UTF-8编码或7位ASCII文本,且不能超过232。 | string | String | str/unicode | string | String (UTF-8) | string | string | String |
bytes | 可以包含不超过232的任意字节序列。 | string | ByteString | str | []byte | String (ASCII-8BIT) | ByteString | string | List |
字段名称
字段名称的命名与C、Java等语言的变量命名方式几乎是相同的
protobuf 建议字段的命名采用以下划线分隔的驼峰式
字段编码值
有了该值,通信双方才能互相识别对方的字段,相同的编码值,其限定修饰符和数据类型必须相同,编码值的取值范围为:1 ~ 2^32 (4294967296)
其中 1 ~ 15的编码时间和空间效率都是最高的,编码值越大,其编码的时间和空间效率就越低
1900 ~ 2000 编码值为 Google protobuf 系统内部保留值,建议不要在项目中使用
字段默认值
当在传递数据时,对于required数据类型,如果用户没有设置值,则使用默认值传递到对端
定义service
- 如果想要将消息类型用在 RPC 系统中,可以在
.proto
文件中定义一个 RPC 服务接口,protocol buffer 编译器会根据所选择的不同语言生成服务接口代码 - 生成的接口代码作为客户端与服务端的约定,服务端必须实现定义的所有接口方法,客户端直接调用同名方法向服务端发起请求(即便业务上不需要参数也必须指定一个请求消息,一般会定义一个空message)
比如,想要定义一个 RPC 服务并具有一个方法,该方法接收 SearchRequest 并返回一个 SearchResponse,此时可以在.proto
文件中进行如下定义:
service SearchService {
rpc Search(SearchRequest) returns (SearchResponse) {}
}
定义Message
- 一个 message 类型定义描述了一个请求或响应的消息格式,可以包含多种类型字段
- 字段名用小写,转为 go 文件后自动变为大写,message 就相当于结构体
添加更多 Message 类型
一个 .proto 文件中可以定义多个消息类型,一般用于同时定义多个相关的消息,例如在同一个 .proto 文件中同时定义搜索请求和响应消息:
// 声明使用的 protobuf 版本
syntax = "proto3"
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = ;
}
message SearchResponse {
}
使用其他 Message
message 支持嵌套使用,作为另一个 message 中的字段类型
message SearchResponse {
repeated Result results = 1;
}
message Result {
string url = 1;
string title = 2;
repeated string snippets = ;
}
Message 嵌套的使用
支持嵌套消息,消息可以包含另一个消息作为字段。也可以在消息内定义一个新的消息。
内部声明的 message 类型名称只可在内部直接使用:
message SearchResponse {
message Result {
string url = 1;
string title = 2;
repeated string snippets = ;
}
repeated Result results = 1;
}
多层嵌套:
message Outer {
message A {
message Inner {
int64 ival = 1;
bool booly = 2;
}
}
message B {
message Inner {
int64 ival = 1;
bool booly = 2;
}
}
}
映射字段
每个映射字段会在Go的结构体中生成一个map[TKey]TValue
类型的字段,其中TKey
是字段的键类型TValue
是字段的值类型。对于下面这个消息定义:
message Bar {}
message Baz {
map<string, Bar> foo = 1;
}
编译器生成Go结构体
type Baz struct {
Foo map[string]*Bar
}
枚举
给出如下枚举
message SearchRequest {
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
Corpus corpus = 1;
...
}
编译器将会生成一个枚举类型和一系列该类型的常量。
.proto 文件编译代码
- 通过定义好的 .proto 文件生成 Go、PHP、Java、Python等代码,需要安装编译器 protoc。
- 使用 protobuf 编译器不同的语言生成的代码格式不同,比如Go:生成一个 .pb.go 文件,每个消息类型对应一个结构体。
具体protoc安装和代码生成可见:
gRPC初体验
也有看到部分项目使用protobuf去替代json去进行前后端数据交换。
参考: