文章目录
前言
Protocol Buffer是Google的语言中立的,平台中立的,可扩展机制的,用于序列化结构化数据 - 对比XML,但更小,更快,更简单。您可以定义数据的结构化,然后可以使用特殊生成的源代码轻松地在各种数据流中使用各种语言编写和读取结构化数据。
定义消息类型
先来看一个非常简单的例子。假设你想定义一个“搜索请求”的消息格式,每一个请求含有一个查询字符串、你感兴趣的查询结果所在的页数,以及每一页多少条查询结果。可以采用如下的方式来定义消息类型的.proto文件了:
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
- 该文件的第一行指定您正在使用
proto3
语法:如果您不这样做,protobuf 编译器将假定您正在使用proto2。这必须是文件的第一个非空的非注释行。 - 所述
SearchRequest
消息定义指定了三个字段(名称/值对),一个用于要在此类型的消息中包含的每个数据片段。每个字段都有一个名称和类型。
指定字段类型
在上面的示例中,所有字段都是标量类型:两个整数(page_number
和result_per_page
)和一个字符串(query
)。但是,您还可以为字段指定合成类型,包括枚举和其他消息类型。
分配标识号
正如上述文件格式,在消息定义中,每个字段都有唯一的一个数字标识符。这些标识符是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变。注:[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留 [1,15]之内的标识号。切记:要为将来有可能添加的、频繁出现的标识号预留一些标识号。
最小的标识号可以从1开始,最大到2^29 - 1, or 536,870,911。不可以使用其中的[19000-19999]的标识号, Protobuf协议实现中对这些进行了预留。如果非要在.proto文件中使用这些预留标识号,编译时就会报警。
指定字段规则
消息字段可以是以下之一:
- 单数:格式良好的消息可以包含该字段中的零个或一个(但不超过一个)。
repeated
:此字段可以在格式良好的消息中重复任意次数(包括零)。将保留重复值的顺序。
在proto3中,repeated
数字类型的字段默认使用packed
编码。
packed
您可以在协议缓冲区编码中找到有关编码的更多信息。
添加更多消息类型
可以在单个.proto
文件中定义多种消息类型。如果要定义多个相关消息,这很有用 - 例如,如果要定义与SearchResponse
消息类型对应的回复消息格式,可以将其添加到相同的消息.proto
:
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
message SearchResponse {
...
}
添加注释
要为.proto
文件添加注释,请使用C / C ++ - 样式//
和/* ... */
语法。
/ * SearchRequest表示搜索查询,带有分页选项
*表明响应中包含哪些结果。* /
message SearchRequest {
string query = 1;
int32 page_number = 2; //我们想要哪个页码?
int32 result_per_page = 3; //每页返回的结果数。
}
保留字段
如果通过完全删除字段或将其注释来更新消息类型,则未来用户可以在对类型进行自己的更新时重用字段编号。如果以后加载相同的旧版本,这可能会导致严重问题.proto
,包括数据损坏,隐私错误等。确保不会发生这种情况的一种方法是指定已删除字段的字段编号(和/或名称,这也可能导致JSON序列化问题)reserved
。如果将来的任何用户尝试使用这些字段标识符,协议缓冲编译器将会抱怨。
message Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}
请注意,您不能在同一reserved
语句中混合字段名称和字段编号。
你的生成是什么.proto
?
当您在a上运行协议缓冲区编译器时.proto
,编译器会生成您所选语言的代码,您需要使用您在文件中描述的消息类型,包括获取和设置字段值,将消息序列化为输出流,并从输入流解析您的消息。
- 对于C ++,编译器会从每个文件生成一个
.h
和一个.cc
文件.proto
,并为您文件中描述的每种消息类型提供一个类。 - 对于Java,编译器生成一个
.java
文件,其中包含每种消息类型的类,以及Builder
用于创建消息类实例的特殊类。 - Python有点不同 - Python编译器生成一个模块,其中包含每个消息类型的静态描述符,
.proto
然后与元类一起使用,以在运行时创建必要的Python数据访问类。 - 对于Go,编译器会为
.pb.go
文件中的每种消息类型生成一个类型的文件。 - 对于Ruby,编译器生成一个
.rb
包含消息类型的Ruby模块的文件。 - 对于Objective-C,编译器从每个文件生成一个
pbobjc.h
和一个pbobjc.m
文件.proto
,其中包含文件中描述的每种消息类型的类。 - 对于C#,编译器会
.cs
从每个文件生成一个文件.proto
,其中包含文件中描述的每种消息类型的类。
您可以按照所选语言的教程(即将推出的proto3版本)了解有关为每种语言使用API的更多信息。有关更多API详细信息,请参阅相关API参考(proto3版本即将推出)。
标量值类型
标量消息字段可以具有以下类型之一 - 该表显示.proto
文件中指定的类型,以及自动生成的类中的相应类型:
.proto type | notes | C ++ type | Java type | Python type [2] | Type | Ruby type | C# type | PHP type |
---|---|---|---|---|---|---|---|---|
double | double | double | float | float64 | float | double | float | |
float | float | float | float | FLOAT32 | float | float | float | |
INT32 | 使用可变长度编码。编码负数的效率低 - 如果您的字段可能有负值,请改用sint32。 | INT32 | INT | INT | INT32 | Fixnum or Bignum (as needed) | INT | Integer |
Int64 | 使用可变长度编码。编码负数的效率低 - 如果您的字段可能有负值,请改用sint64。 | Int64 | long | int / long [3] | Int64 | TWINS | long | Integer/string[5] |
UINT32 | 使用可变长度编码。 | UINT32 | int [1] | int / long [3] | UINT32 | Fixnum or Bignum (as needed) | UINT | Integer |
UINT64 | 使用可变长度编码。 | UINT64 | Long [1] | int / long [3] | UINT64 | TWINS | ULONG | Integer/string[5] |
SINT32 | 使用可变长度编码。签名的int值。这些比常规int32更有效地编码负数。 | INT32 | INT | INT | INT32 | Fixnum or Bignum (as needed) | INT | Integer |
sint64 | 使用可变长度编码。签名的int值。这些比常规int64更有效地编码负数。 | Int64 | long | int / long [3] | Int64 | TWINS | long | Integer/string[5] |
fixed32 | 总是四个字节。如果值通常大于2 28,则比uint32更有效。 | UINT32 | int [1] | int / long [3] | UINT32 | Fixnum or Bignum (as needed) | UINT | Integer |
fixed64 | 总是八个字节。如果值通常大于2 56,则比uint64更有效。 | UINT64 | Long [1] | int / long [3] | UINT64 | TWINS | ULONG | Integer/string[5] |
sfixed32 | 总是四个字节。 | INT32 | INT | INT | INT32 | Fixnum or Bignum (as needed) | INT | Integer |
sfixed64 | 总是八个字节。 | Int64 | long | int / long [3] | Int64 | TWINS | long | Integer/string[5] |
Boolean | Boolean | Boolean | Boolean | Boolean | TrueClass / FalseClass | Boolean | Boolean | |
string | 字符串必须始终包含UTF-8编码或7位ASCII文本。 | string | string | str / unicode[4] | string | String (UTF-8) | string | string |
byte | 可以包含任意字 |