Protocol Buer 技术详解(语言规范)
该系列 的内容主体主要源自于 的官方文档,而代码示例则抽取于当前正在开发的一个公司内部项目的 。这样做的目的主要在于不仅可以保持
文档的良好风格和系统性,同时再结合一些比较实用和通用的用例,这样就更加便于公司内部的培训,以及和广大网友的技术交流。需要说明的是, 的内容并
非 的翻译,其中包含一些经验性总结,与此同时,对于一些不是非常常用的功能并未予以说明,有兴趣的开发者可以直接查阅 的官方文档。
一、为什么使用 ?
在回答这个问题之前,我们还是先给出一个在实际开发中经常会遇到的系统场景。比如:我们的客户端程序是使用 开发的,可能运行自不同的平台,如:
、 或者是 ,而我们的服务器程序通常是基于 平台并使用 开发完成的。在这两种程序之间进行数据通讯时存在多种方式用于设计消息格
式,如:
!"直接传递 # 语言中一字节对齐的结构体数据,只要结构体的声明为定长格式,那么该方式对于 # 程序而言就非常方便了,仅需将接收到的数据按照结构体
类型强行转换即可。事实上对于变长结构体也不会非常麻烦。在发送数据时,也只需定义一个结构体变量并设置各个成员变量的值之后,再以 $%的方式将该二进制数据
发送到远端。反之,该方式对于 开发者而言就会非常繁琐,首先需要将接收到的数据存于 之中,再根据约定的字节序逐个读取每个字段,并将读取后的值
再赋值给另外一个值对象中的域变量,以便于程序中其他代码逻辑的编写。对于该类型程序而言,联调的基准是必须客户端和服务器双方均完成了消息报文构建程序的编写
后才能展开,而该设计方式将会直接导致 程序开发的进度过慢。即便是 阶段,也会经常遇到 程序中出现各种域字段拼接的小错误。
&"使用 '( 协议)'*作为消息报文的格式载体,由该方式生成的报文是基于文本格式的,同时还存在大量的 +, 描述信息,因此将会大大增加网络 -( 的
负担。又由于 +, 解析的复杂性,这也会大幅降低报文解析的性能。总之,使用该设计方式将会使系统的整体运行性能明显下降。
对于以上两种方式所产生的问题, 均可以很好的解决,不仅如此, 还有一个非常重要的优点就是可以保证同一消息报文新旧版本之间
的兼容性。至于具体的方式我们将会在后续的博客中给出。
二、定义第一个 消息。
创建扩展名为". 的文件,如:,,".,并将以下内容存入该文件中。
/0,1
023-4!5
0.4&5
6
这里将给出以上消息定义的关键性说明。
!" 是消息定义的关键字,等同于 中的 #,或是 中的 。
&"/0, 为消息的名字,等同于结构体名或类名。
7"0 前缀表示该字段为必要字段,既在序列化和反序列化之前该字段必须已经被赋值。与此同时,在 中还存在另外两个类似的关键字,
. 和 .,带有这两种限定符的消息字段则没有 0 字段这样的限制。相比于 .,. 主要用于表示数组字段。具体的使用方式在后面的
用例中均会一一列出。
3"23 和 分别表示长整型和字符串型的消息字段,在 中存在一张类型对照表,既 中的数据类型与其他编程语言) #*
中所用类型的对照。该对照表中还将给出在不同的数据场景下,哪种类型更为高效。该对照表将在后面给出。
8"- 和 . 分别表示消息字段名,等同于 中的域变量名,或是 中的成员变量名。
2"标签数字 ! 和 & 则表示不同的字段在序列化后的二进制数据中的布局位置。在该例中,. 字段编码后的数据一定位于 - 之后。需要注意的是该值在同一
中不能重复。另外,对于 而言,标签值为 ! 到 !8 的字段在编码时可以得到优化,既标签值和类型信息仅占有一个 ,标签范围是 !2 到
&93: 的将占有两个 ,而 可以支持的字段数量则为 & 的 &; 次方减一。有鉴于此,我们在设计消息结构时,可以尽可能考虑让 . 类型的字段
标签位于 ! 到 !8 之间,这样便可以有效的节省编码后的字节数量。
三、定义第二个(含有枚举字段) 消息。
##在定义 的消息时,可以使用和 # 代码同样的方式添加注释。
<'1
(==->?495##表示处于离线状态的用户
(>->?4!5##表示处于在线状态的用户
6
<-@1
023-4!5
04&5
0<'475
6
这里将给出以上消息定义的关键性说明(仅包括上一小节中没有描述的)。
!" 是枚举类型定义的关键字,等同于 # 中的 。
&"<' 为枚举的名字。
7"和 # 中的枚举不同的是,枚举值之间的分隔符是分号,而不是逗号。
3"(==->?#(>->? 为枚举值。
8"9 和 ! 表示枚举值所对应的实际整型值,和 # 一样,可以为枚举值指定任意整型值,而无需总是从 9 开始定义。如:
(.1
((>A/?BA(?4!9!5
((<CA/?BA(?4!9&5
/?C/-?D?A<-?'A/?BA(?4!975
((>A/?'A(?4!99!5
((<CA/?'A(?4!99&5
/?C/-?D?A<-?'A/?'A(?4!9975
6
四、定义第三个(含有嵌套消息字段) 消息。
我们可以在同一个". 文件中定义多个 ,这样便可以很容易的实现嵌套消息的定义。如:
<'1