美文网首页
protocol buffers(一)

protocol buffers(一)

作者: 带马界的神秘人 | 来源:发表于2017-12-24 22:04 被阅读0次

这篇文章翻译自https://developers.google.com/protocol-buffers/

protocol buffers是什么?

Protocol buffers 是google的跨语言,跨平台,可扩展的可序列化结构数据,像xml,但是更小,更快和更简单。你只需要定义一次数据结构,然后通过指定语言的生成器,就可以生成指定语言的数据结构和数据流的源码。
Protocol buffers 目前支持 java ,Python,Object-C 和 C++。当使用3.0版本的时候,还支持Go,JavaNano,Ruby和C#,以后还会支持更多语言。

Language Guide (proto3)

定义一个Message类型

先看一个简单的例子。定义一个搜索需要的数据结构格式(SearchRequest ),首先是搜索的内容query字段,然后是当前搜索的页码(page)和每页数据大小(result_per_page)。这里就是你定义的在.proto文件里的Message类型。

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
  • 第一行的syntax: "proto3" 如果你不写,编译器会猜测你用的是proto2,除了注释和空行,这句必须写在最前头。
  • SearchRequest Message定义了三个字段(键值对),每个字段都有类型和名称。

字段类型

在上面的例子中,字段包含两个整形(page_number和result_per_page)和一个字符串(query)。其实还有枚举(enumerations)和其他类型。

分配标签

正如你所见,Message中的每个字段都有一个唯一的数字标签。这些数字标签用于区别这些字段在Message二进制流中的位置,并且当你的Message已经投入使用之后不能再修改。注意这些标签的值如果在1-15之间会占用1byte数据(包括数据类型和标签值),标签的值如果在6-2047之间将占用2byte数据。所以应该使用1-15对于经常传递的Message结构。记得留一些空间给经常传递的Message结构用于以后的添加功能。
最小的标签值是1,最大是229-1或者536,870,911。不能使用19000(FieldDescriptor::kFirstReservedNumbe)到19999(FieldDescriptor::kLastReservedNumber),它们是Protocol Buffers实现中的保留标签值。

字段规则

Message中的字段可以是下面的情况:

  • singular: 一个Message的实例可以有1个或者0个对于这个字段。
  • repeated: 一个Message的实例可以有0到多个,且顺序会被保留。

添加新的Message

多个Message可以被定义到同一个proto文件了。这对要定义多个相关的Message很有用。所以当你要定义一个查询结果的Message时,例如SearchResponse,可以写在同一个proto文件。

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}

message SearchResponse {
 ...
}

添加注释

proto文件的注释与C/C++注释风格一致 ///* ...*/句法。

/* SearchRequest represents a search query, with pagination options to
 * indicate which results to include in the response. */

message SearchRequest {
  string query = 1;
  int32 page_number = 2;  // Which page number do we want?
  int32 result_per_page = 3;  // Number of results to return per page.
}

保留字段

当你删除了Message中的一个字段时,别人可能会重用你的标签值。这会导致加载旧proto的服务器出问题,例如数据冲突,安全bug等等。通过reserved可以防止这种状况的发生。当重用这些字段或者标签值的时,protocol buffer编译器会发出提示。

message Foo {
  reserved 2, 15, 9 to 11;
  reserved "foo", "bar";
}

注意你不能在一个reserved 中同时标记字段和标签值。

通过.proto文件会生成什么?

当编译proto文件时,编译会根据文件中标记的语言生成对应的字段get和set方法,以及Message序列化到输出流和通过输入流生成Message。

  • 对于C++,编译会生成.h和.cc文件,里面包含proto文件中的每个Message对应的Class。
  • 对于java,编译会生成.java文件里面包含对应每个Message的class,和用于生成Message实例的Builder类
  • 对于Python
  • 对于Go,编译会生成一个.pb.go文件,里面包含每个Message对于的类型。
  • 对于Ruby,编译会生成一个.rb文件,里面包含每个Message对应的Ruby模块。
  • 对于JavaNano,编译生成类似java,但是没有生成Builder类。
  • 对于Object-C,编译会生成pbobjc.h和pbobjc.m文件,里面包含proto文件中的每个Message对应的Class。
  • 对于C#,编译会生成.cs文件里面包含对应每个Message的class。

字段类型

一个Message字段可以有下面的类型,这个表格显示proto文件中的类型和对应语言的类型。

.proto Type Notes C++ Type Java Type
double double double
float float float
int32 使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数,那么请使用sint32。 int32 int
int64 使用可变长编码方式。编码负数时不够高效——如果你的字段可能含有负数,那么请使用sint64 int64 long
uint32 使用可变长度编码 uint32 int[1]
uint64 使用可变长度编码 uint64 long[1]
sint32 使用可变长编码方式。有符号的整型值。编码时比通常的int32高效 int32 int
sint64 使用可变长编码方式。有符号的整型值。编码时比通常的int64高效 int64 long
fixed32 总是4个字节。如果数值总是比总是比228大的话,这个类型会比uint32高效。 uint32 int
fixed64 总是8个字节。如果数值总是比总是比256大的话,这个类型会比uint64高效。 uint64 long
sfixed32 总是4个字节。 int32 int
sfixed64 总是8个字节。 int64 long
bool bool boolean
string UTF-8或者7bit-acsii编码的字符串 string string
bytes 可能包含任意顺序的字节数据。 string ByteString

[1] 在java中,无符号32位和64位整形使用的是对应的有符号整形。

相关文章

网友评论

      本文标题:protocol buffers(一)

      本文链接:https://www.haomeiwen.com/subject/lrlxgxtx.html