Golang gRPC实践 连载三 Protobuf语法
Protobuf语法gRPC推荐使用proto3,本节只介绍常用语法,更多高级使用姿势请参考官方文档 Message定义一个message类型定义描述了一个请求或相应的消息格式,可以包含多种类型字段。例如定义一个搜索请求的消息格式,每个请求包含查询字符串、页码、每页数目。 Syntax = "proto3"; message SearchRequest { string query = 1; // 查询字符串 int32 page_number = 2; // 页码 int32 result_per_page = 3; // 每页条数 } 首行声明使用的protobuf版本为proto3 SearchRequest 定义了三个字段,每个字段声明以分号结尾,可使用双斜线 字段类型声明所有的字段需要前置声明数据类型,上面的示例指定了两个数值类型和一个字符串类型。除了基本的标量类型还有复合类型,如枚举、其它message类型等。 标识符Tags可以看到,消息的定义中,每个字段都有一个唯一的数值型标识符。这些标识符用于标识字段在消息中的二进制格式,使用中的类型不应该随意改动。需要注意的是,[1-15]内的标识在编码时只占用一个字节,包含标识符和字段类型。[16-2047]之间的标识符占用2个字节。建议为频繁出现的消息元素使用[1-15]间的标识符。如果考虑到以后可能或扩展频繁元素,可以预留一些标识符。 最小的标识符可以从1开始,最大到229 - 1,或536,870,911。不可以使用[19000-19999]之间的标识符, Protobuf协议实现中预留了这些标识符。在.proto文件中使用这些预留标识号,编译时就会报错。 字段规则
添加更多message类型一个.proto文件中可以定义多个消息类型,一般用于同时定义多个相关的消息,例如在同一个.proto文件中同时定义搜索请求和响应消息: Syntax = "proto3"; // SearchRequest 搜索请求 message SearchRequest { string query = 1; // 查询字符串 int32 page_number = 2; // 页码 int32 result_per_page = 3; // 每页条数 } // SearchResponse 搜索响应 message SearchResponse { ... } 添加注释向.proto文件中添加注释,支持C风格双斜线 保留字段与标识符可以使用reserved关键字指定保留字段和保留标识符: message Foo { reserved 2,15,9 to 11; reserved "foo","bar"; } 注意,不能在一个reserved声明中混合字段名和标识符。 .proto文件编译结果当使用protocol buffer编译器运行
各种语言的更多的使用方法请参考官方API文档 数据类型这里直接引用官方文档的描述: .proto |
C++ |
Java |
Python |
Go |
Ruby |
C# |
@H_502_159@
double
double
double
float
float64
Float
double
float
float
float
float
float32
Float
float
int32
int32
int
int
int32
Fixnum or Bignum
int
int64
int64
long
ing/long[3]
int64
Bignum
long
uint32
uint32
int[1]
int/long[3]
uint32
Fixnum or Bignum
uint
uint64
uint64
long[1]
int/long[3]
uint64
Bignum
ulong
sint32
int32
int
intj
int32
Fixnum or Bignum
int
sint64
int64
long
int/long[3]
int64
Bignum
long
fixed32
uint32
int[1]
int
uint32
Fixnum or Bignum
uint
fixed64
uint64
long[1]
int/long[3]
uint64
Bignum
ulong
sfixed32
int32
int
int
int32
Fixnum or Bignum
int
sfixed64
int64
long
int/long[3]
int64
Bignum
long
bool
bool
boolean
boolean
bool
TrueClass/FalseClass
bool
string
string
String
str/unicode[4]
string
String(UTF-8)
string
bytes
string
ByteString
str
[]byte
String(ASCII-8BIT)
ByteString
关于这些类型在序列化时的编码规则请参考 Protocol Buffer Encoding. [1] java [2] all [3] 64 [4] Python 默认值
针对不同语言的默认值的具体行为参考 generated code guide 枚举(Enum) TODO使用其它Messagemessage SearchResponse { repeated Result results = 1; } message Result { string url = 1; string title = 2; repeated string snippets = 3; } message支持嵌套使用,作为另一message中的字段类型 导入定义(import)可以使用import语句导入使用其它描述文件中声明的类型 import "others.proto"; protocol buffer编译器会在 Message嵌套message SearchResponse { message Result { string url = 1; string title = 2; repeated string snippets = 3; } repeated Result results = 1; } 内部声明的message类型名称只可在内部直接使用,在外部引用需要前置父级message名称,如 message SomeOtherMessage { SearchResponse.Result result = 1; } 支持多层嵌套: message Outer { // Level 0 message MiddleAA { // Level 1 message Inner { // Level 2 int64 ival = 1; bool booly = 2; } } message MiddleBB { // Level 1 message Inner { // Level 2 int32 ival = 1; bool booly = 2; } } } Message更新 TODOMap类型proto3支持map类型声明: map<key_type,value_type> map_field = N; message Project {...} map<string,Project> projects = 1;
包(Packages)在 Syntax = "proto3"; package foo.bar; message Open {...} 在其他的消息格式定义中可以使用包名+消息名的方式来使用类型,如: message Foo { ... foo.bar.Open open = 1; ... } 在不同的语言中,包名定义对编译后生成的代码的影响不同:
定义服务(Service)如果想要将消息类型用在RPC(远程方法调用)系统中,可以在 service SearchService { rpc Search (SearchRequest) returns (SearchResponse) {} } 生成的接口代码作为客户端与服务端的约定,服务端必须实现定义的所有接口方法,客户端直接调用同名方法向服务端发起请求。比较蛋疼的是即便业务上不需要参数也必须指定一个请求消息,一般会定义一个空message。 选项(Options)在定义.proto文件时可以标注一系列的options。Options并不改变整个文件声明的含义,但却可以影响特定环境下处理方式。完整的可用选项可以查看 一些选项是文件级别的,意味着它可以作用于顶层作用域,不包含在任何消息内部、enum或服务定义中。一些选项是消息级别的,可以用在消息定义的内部。当然有些选项可以作用在字段、enum类型、enum值、服务类型及服务方法中。但是到目前为止,并没有一种有效的选项能作用于这些类型。 一下是一些常用的选择:
基本规范描述文件以
|