的应用和法则

ProtocolBuffer拥有多项比XML更高级的串行化结构数据的表征,ProtocolBuffer:

谷歌 Protocol Buffer 的利用和公理(转)

简介

如何是 谷歌 Protocol Buffer?
若是您在网上搜索,应该会收获近似那样的文字介绍:

谷歌 Protocol Buffer( 简称 Protobuf) 是 谷歌(Google)集团里面包车型大巴交集语言数据标准,近期早就正在选取的有当先 48,162
种报文格式定义和超过 12,183 个 .proto 文件。他们用于 HavalPC
系统和不断数据存款和储蓄系统。

Protocol Buffers
是一种轻便神速的结构化数据存款和储蓄格式,可以用于结构化数据串行化,或许说种类化。它很合乎做多少存款和储蓄或
EscortPC
数据调换格式。可用以通信协议、数据存款和储蓄等世界的言语非亲非故、平台毫无干系、可增添的种类化结构数据格式。近日提供了
C++、Java、Python 三种语言的 API。

唯恐你和自身同样,在首先次看完那一个介绍后照旧不晓得 Protobuf
毕竟是如何,那么自个儿想贰个简短的例证应该相比较有助于了然它。

三个总结的事例安装 谷歌 Protocol Buffer

在网站 http://code.google.com/p/protobuf/downloads/list上得以下载
Protobuf 的源代码。然后解压缩编制写翻译安装便得以运用它了。

安装步骤如下所示:

tar -xzf protobuf-2.1.0.tar.gz cd protobuf-2.1.0 ./configure
–prefix=$INSTALL_DIR make make check make install

至于不难例子的叙说

自家打算采用 Protobuf 和 C++ 开发2个优异简练的事例程序。

该程序由两有个别组成。第叁有个别被号称 Writer,第2有的号称 Reader。

Writer 负责将一些结构化的数额写入一个磁盘文件,Reader
则承担从该磁盘文件中读取结构化数据并打字与印刷到荧屏上。

准备用于演示的结构化数据是 HelloWorld,它含有七个主导数据:

  • ID,为3个平头门类的多少
  • Str,那是一个字符串

书写 .proto 文件

第2大家要求编写制定二个 proto 文件,定义大家先后中必要处理的结构化数据,在
protobuf 的术语中,结构化数据被称之为 Message。proto 文件充裕接近 java
大概 C 语言的数量定义。代码清单 1 展现了例子应用中的 proto 文件内容。

清单 1. proto 文件

package lm; message helloworld { required int32 id = 1; // ID required
string str = 2; // str optional int32 opt = 3; //optional field }

3个相比好的习惯是当真对照 proto 文件的文书名。比如将命名规则定于如下:

packageName.MessageName.proto

在上例中,package 名字叫做 lm,定义了一个音讯helloworld,该音信有四个分子,类型为 int32 的 id,另三个为项目为 string
的积极分子 str。opt 是一个可选的积极分子,即新闻中能够不含有该成员。

编译 .proto 文件

写好 proto 文件从此就足以用 Protobuf
编译器将该文件编写翻译成目的语言了。本例中大家将利用 C++。

一经你的 proto 文件存放在 $STiguanC_DI路虎极光上边,您也想把变化的文件放在同四个目录下,则足以行使如下命令:

protoc -I=$SRC_DIR –cpp_out=$DST_DIR $SRC_DIR/addressbook.proto

命令将生成三个文件:

lm.helloworld.pb.h , 定义了 C++ 类的头文件

lm.helloworld.pb.cc , C++ 类的兑现公文

在扭转的头文件中,定义了1个 C++ 类 helloworld,后边的 Writer 和 Reader
将选用那几个类来对消息进行操作。诸如对新闻的成员进行赋值,将新闻系列化等等都有照应的章程。

编写 writer 和 Reader

如 前所述,Writer
将把一个结构化数据写入磁盘,以便别的人来读取。假若我们不行使
Protobuf,其实也有为数不少的选拔。一个可能的主意是将数据转换为字符串,然后将字符串写入磁盘。转换为字符串的章程能够应用
sprintf(),那分外简单。数字 123 能够成为字符串”123”。

那般做就像是没有怎么不妥,但是仔细考虑一下就会发现,这样的做 法对写 Reader
的格外人的须要相比高,Reader 的笔者必须了 Writer
的底细。比如”123”能够是单个数字 123,但也得以是七个数字 1,2 和
3,等等。这么说来,大家还必须让 Writer 定义一种分隔符一样的字符,以便
Reader
能够正确读取。但分隔符可能还会挑起别的的如何难点。最终我们发现3个简易的
Helloworld 也亟需写过多甩卖音信格式的代码。

假设运用 Protobuf,那么那么些细节就足以不需求应用程序来设想了。

使 用 Protobuf,Writer 的干活极粗略,要求处理的结构化数据由 .proto
文件讲述,经过上一节中的编译进度后,该数据化结构对应了三个 C++
的类,并定义在 lm.helloworld.pb.h 中。对于本例,类名为 lm::helloworld。

Writer 必要 include 该头文件,然后便足以运用这些类了。

现行,在 Writer 代码中,将要存入磁盘的结构化数据由3个 lm::helloworld
类的对象表示,它提供了一文山会海的 get/set
函数用来修改和读取结构化数据中的数据成员,只怕叫 田野同志。

当大家要求将该结构化数据保存到磁盘上时,类 lm::helloworld
已经提供相应的格局来把一个错综复杂的数据变成二个字节种类,大家得以将以此字节种类写入磁盘。

对 于想要读取这几个数量的程序来说,也只须求运用类 lm::helloworld
的对应反连串化方法来将这么些字节系列重新更换会结构化数据。那同大家早先时格外“123”的想法近乎,但是Protobuf
想的远远比大家相当粗糙的字符串转换要到家,因而,我们比不上放心将那类事情交给
Protobuf 吧。

程序清单 2 示范了 Writer 的机要代码,您一定会认为很简单吗?

清单 2. Writer 的关键代码

#include “lm.helloworld.pb.h” … int main(void) { lm::helloworld msg1;
msg1.set_id(101); msg1.set_str(“hello”); // Write the new address book
back to disk. fstream output(“./log”, ios::out | ios::trunc |
ios::binary); if (!msg1.SerializeToOstream(&output)) { cerr <<
“Failed to write msg.” << endl; return -1; } return 0; }

Msg1 是三个 helloworld 类的靶子,set_id() 用来设置 id
的值。SerializeToOstream 将指标类别化后写入三个 fstream 流。

代码清单 3 列出了 reader 的显要代码。

清单 3. Reader

#include “lm.helloworld.pb.h” … void ListMsg(const lm::helloworld &
msg) { cout << msg.id() << endl; cout << msg.str()
<< endl; } int main(int argc, char* argv[]) { lm::helloworld
msg1; { fstream input(“./log”, ios::in | ios::binary); if
(!msg1.ParseFromIstream(&input)) { cerr << “Failed to parse
address book.” << endl; return -1; } } ListMsg(msg1); … }

同一,Reader 注明类 helloworld 的对象 msg1,然后利用 ParseFromIstream
从八个 fstream 流中读打消息并反类别化。此后,ListMsg 中选拔 get
方法读取音信的内部音信,并举办打字与印刷输出操作。

运作结果

运营 Writer 和 Reader 的结果如下:

>writer >reader 101 Hello

Reader 读取文件 log
中的连串化音信并打字与印刷到荧屏上。本文中保有的事例代码都得以在附属类小部件中下载。您能够亲自感受一下。

以此事例本身并无意义,但如果您稍加修改就能够将它成为更为管用的次第。比如将磁盘替换为互连网socket,那么就能够完毕基于网络的数据交换职分。而存款和储蓄和置换就是 Protobuf
最有效的应用领域。

和任何类似技术的相比

看完这么些简单的例子之后,希望您曾经能掌握 Protobuf
能做哪些了,那么你恐怕会说,世上还有很多其余的类似技术啊,比如
XML,JSON,Thrift 等等。和她俩对待,Protobuf 有何样分化呢?

粗略说来 Protobuf 的要紧优点正是:不难,快。

那有测试为证,项目 thrift-protobuf-compare 比较了这么些看似的技艺,图 1
出示了该类型的一项测试结果,Total Time.

图 1. 属性测试结果葡萄娱乐场 1

Total Time
指叁个对象操作的成套时间,包涵创立对象,将指标种类化为内部存款和储蓄器中的字节系列,然后再反类别化的一体进度。从测试结果能够看看
Protobuf
的大成很好,感兴趣的读者可以自行到网站 http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking上询问更详尽的测试结果。

Protobuf 的优点

Protobuf 有如
XML,但是它更小、更快、也更简短。你能够定义自个儿的数据结构,然后使用代码生成器生成的代码来读写这么些数据结构。你甚至能够在无需重新布署程序的情况下更新数据结构。只需利用 Protobuf
对数据结构实行1回描述,即可使用各类差异语言或从各类不一致数据流中对您的结构化数据轻松读写。


有三个格外棒的风味,即“向后”包容性好,人们不要破坏已布署的、依靠“老”数据格式的次序就足以对数据结构实行升级。这样你的程序就能够不必顾虑因为音信结构的转移而招致的科学普及的代码重构可能迁移的难点。因为加上新的音讯中的
田野(field) 并不会滋生已经昭示的次序的其余变更。

Protobuf 语义更清晰,无需类似 XML 解析器的东西(因为 Protobuf 编写翻译器会将
.proto 文件编写翻译生成对应的数据访问类以对 Protobuf
数据开始展览类别化、反类别化操作)。

动用 Protobuf 无需学习复杂的文书档案对象模型,Protobuf
的编制程序情势比较和谐,不难命理术数,同时它拥有突出的文书档案和演示,对于爱好简单事物的大千世界而言,Protobuf
比其余的技巧尤其有吸重力。

Protobuf 的不足

Protbuf 与 XML 比较也有不足之处。它效益不难,无法用来表示复杂的定义。

XML 已经济体改成八种行业标准的编写制定工具,Protobuf 只是 Google公司之中选用的工具,在通用性上还差很多。

由 于文本并不符合用来叙述数据结构,所以 Protobuf
也不吻合用来对依据文本的号子文书档案(如 HTML)建立模型。此外,由于 XML
具有某种程度上的自解释性,它能够被人直接读取编辑,在那或多或少上 Protobuf
不行,它以二进制的艺术存储,除非你有 .proto 定义,不然你无法直接读出
Protobuf 的其余内容【 2 】。

高等应用话题更复杂的 Message

到此地甘休,大家只交付了多个简单易行的远非任何用处的例证。在实际上利用中,人们频仍须要定义特别复杂的
Message。大家用“复杂”那么些词,不仅仅是指从个数上说有更加多的 田野先生s
也许更六种类的 田野(field)s,而是指更是复杂的数据结构:

嵌套 Message

嵌套是三个神奇的定义,一旦拥有嵌套能力,音信的表达能力就会12分强劲。

代码清单 4 给出3个嵌套 Message 的例证。

清单 4. 嵌套 Message 的例子

message Person { required string name = 1; required int32 id = 2; //
Unique ID number for this person. optional string email = 3; enum
PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber {
required string number = 1; optional PhoneType type = 2 [default =
HOME]; } repeated PhoneNumber phone = 4; }

在 Message Person 中,定义了嵌套消息 PhoneNumber,并用来定义 Person
消息中的 phone 域。这使得人们能够定义尤其错综复杂的数据结构。

4.1.2 Import Message

在三个 .proto 文件中,还足以用 Import 关键字引入在别的 .proto
文件中定义的音信,那足以称做 Import Message,可能 Dependency Message。

譬如下例:

清单 5. 代码

import common.header; message youMsg{ required common.info_header
header = 1; required string youPrivateData = 2; }

其中 ,common.info_header定义在common.header包内。

Import Message 的用途重要在于提供了方便的代码管理机制,类似 C
语言中的头文件。您能够将一部分公用的 Message 定义在一个 package
中,然后在别的 .proto 文件中引入该 package,进而使用在那之中的音讯定义。

谷歌(Google) Protocol Buffer 能够很好地援助嵌套 Message 和引入
Message,从而让定义复杂的数据结构的做事变得十一分轻松欢悦。

动态编写翻译

一般景观下,使用 Protobuf 的人们都会先写好 .proto 文件,再用 Protobuf
编写翻译器生成目标语言商讨所需求的源代码文件。将那个生成的代码和应用程序一起编写翻译。

不过在某且状态下,人们不可能先行驾驭 .proto
文件,他们必要动态处理局地不解的 .proto
文件。比如一个通用的音讯转载中间件,它不容许预感必要处理如何的消息。那亟需动态编写翻译.proto 文件,并运用在那之中的 Message。

Protobuf 提供了 google::protobuf::compiler
包来成功动态编写翻译的作用。首要的类叫做 importer,定义在 importer.h
中。使用 Importer 至极简单,下图显示了与 Import
和其他多少个非常重要的类的关联。

图 2. Importer 类葡萄娱乐场 2

Import 类对象中带有四个第叁的对象,分别为处理错误的
MultiFileErrorCollector 类,定义 .proto 文件源目录的 SourceTree 类。

上面依旧经超过实际例证实这几个类的涉嫌和采用呢。

对此给定的 proto 文件,比如
lm.helloworld.proto,在程序中动态编译它只供给很少的一部分代码。如代码清单
6 所示。

清单 6. 代码

google::protobuf::compiler::MultiFileErrorCollector errorCollector;
google::protobuf::compiler::DiskSourceTree sourceTree;
google::protobuf::compiler::Importer importer(&sourceTree,
&errorCollector); sourceTree.MapPath(“”, protosrc);
importer.import(“lm.helloworld.proto”);

先是构造二个 importer 对象。构造函数须要五个输入参数,贰个是 source Tree
对象,该指标内定了存放 .proto 文件的源目录。第①个参数是1个 error
collector 对象,该对象有1个 AddError 方法,用来处精通析 .proto
文件时遇上的语法错误。

随后,须要动态编译3个 .proto 文件时,只需调用 importer 对象的 import
方法。分外不难。

那正是说大家怎么采用动态编写翻译后的 Message 呢?我们必要首先领会多少个别的的类

Package google::protobuf::compiler 中提供了以下多少个类,用来表示2个.proto 文件中定义的 message,以及 Message 中的 田野同志,如图所示。

图 3. 逐项 Compiler
类之间的关联葡萄娱乐场 3

类 FileDescriptor 表示二个编写翻译后的 .proto 文件;类 Descriptor
对相应文件中的贰个 Message;类 FieldDescriptor 描述2个 Message
中的2个现实 Field。

比如说编写翻译完 lm.helloworld.proto 之后,能够因此如下代码获得lm.helloworld.id 的定义:

清单 7. 得到 lm.helloworld.id 的概念的代码

const protobuf::Descriptor *desc =
importer_.pool()->FindMessageTypeByName(“lm.helloworld”); const
protobuf::FieldDescriptor* field = desc->pool()->FindFileByName
(“id”);

透过 Descriptor,FieldDescriptor
的各类法子和品质,应用程序能够取得各样关于 Message 定义的新闻。比如通过
田野先生->name() 获得 田野同志的名字。那样,您就能够利用3个动态定义的消息了。

编辑新的 proto 编写翻译器

随 谷歌 Protocol Buffer 源代码一起发表的编写翻译器 protoc 帮衬 3
种编制程序语言:C++,java 和 Python。但使用 谷歌(Google) Protocol Buffer 的
Compiler 包,您能够付出出协理别的语言的新的编写翻译器。

类 CommandLineInterface 封装了 protoc
编写翻译器的前端,包含命令行参数的辨析,proto
文件的编写翻译等功效。您所供给做的是兑现类 CodeGenerator
的派生类,达成诸如代码生成等后端工作:

先后的大致框架如图所示:

图 4. XML 编写翻译器框图葡萄娱乐场 4

在 main() 函数内,生成 CommandLineInterface 的靶子 cli,调用其
RegisterGenerator() 方法将新语言的后端代码生成器 yourG 对象注册给 cli
对象。然后调用 cli 的 Run() 方法即可。

这么生成的编写翻译器和 protoc 的应用办法同样,接受平等的命令行参数,cli
将对用户输入的 .proto
实行词菲律宾语法等分析工作,最终生成2个语法树。该树的构造如图所示。

图 5. 语法树葡萄娱乐场 5

其 根节点为贰个 FileDescriptor
对象(请参见“动态编写翻译”一节),并视作输入参数被传到 yourG 的 Generator()
方法。在这几个模式内,您能够遍历语法树,然后生成对应的你所必要的代码。不难说来,要想完毕二个新的
compiler,您只必要写三个 main 函数,和三个落到实处了措施 Generator()
的派生类即可。

在本文的下载附属类小部件中,有1个参阅例子,将 .proto 文件编写翻译生成 XML 的
compiler,能够当作参照。

Protobuf 的更加多细节

人们直接在强调,同 XML 相比较, Protobuf
的要紧优点在于品质高。它以神速的二进制模式存款和储蓄,比 XML 小 3 到 10 倍,快
20 到 100 倍。

对于这一个 “小 3 到 10 倍”,“快 20 到 100
倍”的传道,庄敬的程序员要求多少个分解。由此在本文的尾声,让大家多少尖锐
Protobuf 的在这之中贯彻啊。

有两项技艺确定保证了使用 Protobuf 的次第能得到相对于 XML 非常大的品质提升。

先是点,我们得以洞察 Protobuf 种类化后的新闻内容。您能够见到 Protocol
Buffer
消息的表示尤其紧密,那象征新闻的体量裁减,自然要求更少的财富。比如网络上传输的字节数更少,须要的
IO 更少等,从而增强品质。

其次点大家要求通晓 Protobuf 封解包的大约进度,从而了然为何会比 XML
快很多。

Google Protocol Buffer 的 Encoding

Protobuf 系列化后所生成的二进制消息分外紧密,那得益于 Protobuf
采取的尤其巧妙的 Encoding 方法。

着眼消息结构此前,让本身第叁要介绍3个名为 Varint 的术语。

Varint
是一种紧密的象征数字的办法。它用一个或多少个字节来代表三个数字,值越小的数字运用越少的字节数。这能压缩用来代表数字的字节数。

比 如对于 int32 类型的数字,一般须求 4 个 byte 来表示。不过利用
Varint,对于非常小的 int32 类型的数字,则足以用 1 个 byte
来表示。当然一切都有好的也有不佳的一边,选取 Varint
表示法,大的数字则须要 5 个 byte
来表示。从计算的角度来说,一般不会具备的音讯中的数字都以时局,由此一大全场所下,接纳Varint 后,能够用更少的字节数来表示数字音讯。上边就详细介绍一下 Varint。

Varint 中的各类 byte 的最高位 bit 有破例的意义,假使该位为 1,表示继续的
byte 也是该数字的一有个别,假设该位为 0,则截至。别的的 7 个 bit
都用于表示数字。因而小于 128 的数字都得以用二个 byte 表示。大于 128
的数字,比如 300,会用多少个字节来表示:1010 1100 0000 0010

下图演示了 谷歌 Protocol Buffer 怎么着分析八个bytes。注意到终极总计前将四个 byte 的职位互相沟通过一次,那是因为 谷歌Protocol Buffer 字节序采取 little-endian 的法子。

图 6. Varint 编码葡萄娱乐场 6

音信经过种类化后会成为3个二进制数据流,该流中的数据为一文山会海的 Key-Value
对。如下图所示:

图 7. Message Buffer葡萄娱乐场 7

选择那种 Key-Pair 结构无需采纳分隔符来划分不一致的 Field。对于可选的
Field,如若音信中不设有该 田野同志,那么在最后的 Message Buffer 中就没有该
田野(field),这么些特征都助长节约音讯笔者的轻重。

以代码清单 1 中的新闻为例。若是大家转变如下的一个音信 Test1:

Test1.id = 10; Test1.str = “hello”;

则最终的 Message Buffer 中有多少个 Key-Value 对,三个相应音信中的
id;另三个应和 str。

Key 用来标识具体的 田野,在解包的时候,Protocol Buffer 根据 Key
就足以知晓相应的 Value 应该相应于新闻中的哪一个 田野同志。

Key 的概念如下:

(field_number << 3) | wire_type

能够见见 Key 由两片段构成。第三片段是 田野先生_number,比如新闻lm.helloworld 中 field id 的 田野_葡萄娱乐场,number 为 1。第一部分为
wire_type。表示 Value 的传导类型。

Wire Type 恐怕的类型如下表所示:

表 1. Wire Type Type Meaning Used For 0 Varint int32, int64,
uint32, uint64, sint32, sint64, bool, enum 1 64-bit fixed64, sfixed64,
double 2 Length-delimi string, bytes, embedded messages, packed repeated
fields 3 Start group Groups (deprecated) 4 End group Groups (deprecated)
5 32-bit fixed32, sfixed32, float

在我们的例证个中,田野先生 id 所使用的数据类型为 int32,因而相应的 wire
type 为 0。细心的读者或者会看出在 Type 0 所能表示的数据类型中有 int32 和
sint32 这五个可怜相近的数据类型。谷歌 Protocol Buffer
不一样它们的最主要意图也是为了削减 encoding 后的字节数。


计算机内,三个负数一般会被代表为三个极大的平头,因为电脑定义负数的标志位为数字的参天位。假若采用Varint 表示二个负数,那么早晚要求 5 个 byte。为此 谷歌 Protocol Buffer
定义了 sint32 那类别型,选择 zigzag 编码。

Zigzag 编码用无符号数来代表有号子数字,正数和负数交错,那正是 zigzag
这一个词的含义了。

如图所示:

图 8. ZigZag 编码葡萄娱乐场 8

行使 zigzag 编码,相对值小的数字,无论正负都足以动用较少的 byte
来代表,足够利用了 Varint 那种技能。

其余的数据类型,比如字符串等则应用类似数据库中的 varchar
的意味方法,即用2个 varint
表示长度,然后将别的部分紧跟在那几个长度部分之后即可。

通过以上对 protobuf Encoding 方法的牵线,想必你也曾经发现 protobuf
音信的内容小,适于网络传输。如若你对那个关于技术细节的叙述不够耐心和兴趣,那么下边那一个大致而直观的相比较应该能给你特别深远的纪念。

对此代码清单 1 中的消息,用 Protobuf 系列化后的字节体系为:

08 65 12 06 48 65 6C 6C 6F 77

而一旦用 XML,则类似那样:

31 30 31 3C 2F 69 64 3E 3C 6E 61 6D 65 3E 68 65 6C 6C 6F 3C 2F 6E 61 6D
65 3E 3C 2F 68 65 6C 6C 6F 77 6F 72 6C 64 3E 一共 伍拾2个字节,这几个奇怪的数字须要有些解释一下,其意思用 ASCII 表示如下:
<helloworld> <id>101</id>
<name>hello</name> </helloworld>

封解包的进度

第叁大家来通晓一 下 XML 的封解包进程。XML
供给从文件中读取出字符串,再更换为 XML 文书档案对象组织模型。之后,再从 XML
文书档案对象协会模型中读取钦定节点的字符串,最终再将以此字符串转换来钦赐项指标变量。那些进度分外复杂,其中将XML 文件转换为文书档案对象协会模型的长河一般必要完结词法文法分析等大气消耗
CPU 的繁杂总结。

回望 Protobuf,它只要求简单地将1个二进制类别,依照钦赐的格式读取到 C++
对应的构造类型中就足以了。从上一节的讲述能够看出音信的 decoding
进程也得以由此几个位移操作组成的表明式总结即可完结。速度相当的慢。

为了证实那并不是自身拍脑袋随意想出来的传教,上面让大家大致解析一下
Protobuf 解包的代码流程吧。

以代码清单 3 中的 里德r 为例,该程序首先调用 msg1 的 ParseFromIstream
方法,那一个点子分析从文件读入的二进制数据流,并将分析出来的数量给予
helloworld 类的相应数额成员。

该进度能够用下图表示:

图 9. 解包流程图葡萄娱乐场 9

一体解析进度需求 Protobuf 本身的框架代码和由 Protobuf
编写翻译器生成的代码共同达成。Protobuf 提供了基类 Message 以及 Message_lite
作为通用的 Framework,,CodedInputStream 类,WireFormatLite
类等提供了对二进制数据的 decode 成效,从 5.1 节的分析来看,Protobuf
的解码能够经过多少个简易的数学生运动算完结,无需复杂的词西班牙语法分析,由此ReadTag() 等办法都不行快。
在那个调用路径上的其余类和艺术都非凡简单,感兴趣的读者能够自行阅读。
相对于 XML 的剖析进度,以上的流程图实在是相当简单吧?那也正是 Protobuf
功用高的首个原因了。

 

结束语

屡次明白越来越多,人们就会越觉得自个儿无知。作者惶恐地发现本身竟然写了一篇关于种类化的小说,文中必然有过多想当不过傲慢的东西,还指望各位能够去伪存真,更期望真的高手能不吝赐教,给我写信。多谢。

Protocol Buffers
之所以解析速度快、所占体积小,不小程度上是由它体系化的编码特点来决定的。

为了消除那么些题材,Protocol
Buffers定义了sint32/sint64属性,他们选取了“之字形”(ZigZag)编码的主意,将负数编码成正数,交替举行。看了下表就很好驾驭了:

行使varints的格局编码有记号的整数,作用比较差,因为负数的最高位是1,那样就造成了情景好像于编码多少个十分大的数。

2.2 Key-Value

Protobuf-net: the unofficial manual
http://www.codeproject.com/Articles/642677/Protobuf-net-the-unofficial-manual

 

· 快20-100倍

当这么些报文编码到ProtocolBuffer的二进制格式(
http://code.google.com/apis/protocolbuffers/docs/encoding.html
)时(上边的文本仅用于调试和编辑),它只要求28字节和100-200ns的解析时间。而XML的版本要求69字节(除去空白)和5000-一千0ns的辨析时间。

<person>
<name>John Doe</name>
<email>jdoe@example.com</email>
</person>

Beetle使用Protobuf.net进行对象种类化传输

2.1 Base 128 Varints

· 更少的歧义

  1. 阳台毫不相关、语言毫不相关
  2. 高性能 比XML块20-100倍
  3. 体积小 比XML小3-10倍
  4. 使用简便
  5. 包容性好

② 、message的编码特点

· 能够便宜的变型数据存取类

Protocol Buffers具有以下特点:

表3:Zig-Zag编码规则

自然,操作ProtocolBuffer也很简短:

  1. 变长编码的整数,它大概含有多少个byte,对于各类byte的8人,个中后五个人代表数值,最高的一个人表示是还是不是还有还有另二个byte,0象征从未,1代表有;
  2. 越后面的byte表示数值的没有,越前面的byte表示数值的上位;

cout << “Name: “
<<
person.getElementsByTagName(“name”)->item(0)->innerText()
<< endl;
cout << “E-mail: “
<<
person.getElementsByTagName(“email”)->item(0)->innerText()
<< end;

  • 08代表的是key 0 0001 000,
    最高位为0,表示这几个key为3个byte,中间三人代表a的数字小名,最后贰位代表a的属性类型;
  • 96 01意味着的是value,二进制为:1001 0110 0000 0001
    → 001 0110 000 0001(去掉最高位)
    → 22 + 1*2^7 = 150

自然,ProtocolBuffer并不是在别的时候都比XML更适于,例如ProtocolBuffer无法对贰个依照标记文本的文书档案建立模型,因为您根本没办法方便的在文件中插入结构。其它,XML是有利于人类阅读和编辑的,而ProtocolBuffer则不是。还有XML是自解释的,而
ProtocolBuffer仅在你抱有报文格式定义的 .proto 文件时才有含义。

Working with Protobuf WCF Services
http://www.drdobbs.com/windows/working-with-protobuf-wcf-services/240159282?pgno=1

Protocol Buffers选拔了Base 128 Varints来变长编码整数:

Protocol buffers are Google’s language-neutral, platform-neutral,
extensible mechanism for serializing structured data – think XML, but
smaller, faster, and simpler
. You define how you want your data to be
structured once, then you can use special generated source code to
easily write and read your structured data to and from a variety of data
streams and using a variety of languages – Java, C++, or Python. You can
even update your data structure without breaking deployed programs that
are compiled against the “old” format.(摘自Protocol
Buffers官网

2.3 Zig-Zag

如前所述,Protocol
Buffers的message是一多级的key-value对,在二进制数据中,使用varints数字(蕴含了外号以及品质类型音讯)来作为key,进而通过由PB编写翻译器生成的代码来组织以及解析数据。
Protocol Buffers将 key编码成上边包车型客车组织:
X YYYY ZZZ
内部:最高位X表示是还是不是还有继续的byte来编码数字别称;YYYY用于编码别名,定义了剩余16脾气子,则要求用到额外的byte,所以出现频率高的字段应当取1-16的别称);ZZZ表示那些字段的档次,PB帮忙的性质的应和规则如下表:

· 小3-10倍

例子:
300 varints 编码为:1010 1100 0000 0010
演讲如下:
300的2进制编码为:0001 0010 1100
依据刚才的规则,高低位颠倒,截取最后的7为放在第四个byte,则率先byte为1010
1100(个中最高位1意味着,后续还有byte);接着剩下的内容放到第三个byte,为0000
0010(个中最高位0表示,后续无byte,这么些数到此地甘休了)。
于是,合在一起为 1010 1100 0000 0010;

 

Type Meaning Used For
0 Varint int32, int64, uint32, uint64, sint32,sint64, bool, enum
1 64-bit fixed64, sfixed64, double
2 Length-delimited string, bytes, embedded messages,packed repeated fields
3 Start group groups (deprecated)
4 End group groups (deprecated)
5 32-bit fixed32, sfixed32, floa

谷歌 Protocol Buffer
的行使和公理

cout << “Name: ” << person.name() << endl;
cout << “E-mail: ” << person.email() << endl;

有关小说:

#ProtocolBuffer的公文表示
#那不是常规时行使的二进制数据
person {
name: “John Doe”
email: “jdoe@example.com
}

Protocol Buffers and WCF
http://blogs.msdn.com/b/dmetzgar/archive/2011/03/29/protocol-buffers-and-wcf.aspx

  1. Protocol Buffers的介绍

而XML的你必要:

WCF服务上使用protobuf

3.为什么不要XML?

对应的ProtocolBuffer报文则如下:

Signed Original Encoded As
0 0
-1 1
1 2
-2 3
2147483647 4294967294
2147483648 4294967295

接纳那几个点子,能够使得地节约存款和储蓄空间,也能增高解析作用。领悟了上述内容,对于任何数据类型的编码,也是很好驾驭的,大家能够参见官方文书档案,那里不做详述。

譬如说,让我们看看怎么样在XML中国建工业总会公司模Person的name和email字段:

· 更简单

protocol
buffers是google提供的一种将结构化数据实行系列化和反体系化的不二法门,其优点是言语中立,平博洛尼亚立,可扩展性好,如今在google内部多量用以数据存款和储蓄,通讯协议等地点。Protocol
Buffers在功用上接近XML,不过类别化后的数额更小,解析更快,使用上更简短。用户只要服从proto语法在.proto文件中定义好数据的布局,就足以运用Protocol
Buffers提供的工具(protoc)自动生成处理数据的代码,使用那些代码就能在程序中有益的通过各个数码流读写多少。PB最近支撑Java,
C++和Python3种语言。其余,Protocol
Buffers还提供了很好的向后杰出,即旧版本的顺序能够平常处理新本子的数据,新本子的主次也能寻常处理旧版本的数量。

表2:PB 属性对应规则
例子:
required int32 a=1; 在动用中给a赋值150 ,体系化后08 96 01

.net自带二进制体系化,XML连串化和ProtoBuf系列化的回落比较

玩转Protocol
Buffers