- 浏览: 504807 次
- 性别:
- 来自: 广州
最新评论
-
cppmule:
Play!在国内实际产品级应用案例有吗?有哪些公司在用?国外的 ...
play总结性介绍 -
你好javaword:
netty的个人使用心得 -
hyfwuhui:
java 并发环境下使用ConcurrentHashMap -
asialee:
朋在无锡 写道可以将Channels使用静态导入的方式:imp ...
netty的个人使用心得 -
朋在无锡:
可以将Channels使用静态导入的方式:import sta ...
netty的个人使用心得
Protocol Buffers 语法指南
Posted on 2013 年 4 月 11 日 by Fowler Zhang
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息石头儿和本声明。否则将追究法律责任。http://shitouer.cn/2013/04/google-protocol-buffers-tutorial/
1. 概述
前两篇文章,我们概括介绍《Google Protocol Buffers 概述》以及带领大家简单的《Google Protocol Buffers 入门》,接下来,再稍微详细一点介绍Protocol Buffers书写语言。该篇文章主要讲解如何使用PB语言构建数据,包括.proto文件语法及如果使用.proto文件生成数据存取类。
本篇主要包括:
定义一个PB message类型
介绍PB 数据类型
Optional字段及其默认值
枚举类型
使用其他Message类型作为filed类型
嵌套类型
更新Message
2. 定义一个PB message类型
假如现在需要定义搜索请求的message格式,每条message包含三个字段:搜索语句(query string),需要的返回结果页数(page_number),以及该页上的结果数。可如下定义.proto文件。
?
1
2
3
4
5
message SearchRequest {
required string query = 1;
optional int32 page_number = 2;
optional int32 result_per_page = 3;
}
该message定义声明三个字段(name/value pairs),每个字段有一个名字和类型。
2.1 声明字段类型
上例中,所有的字段类型均为标准类型:两个整型和一个字符串类型。当然,也可以指定复合类型:枚举类型和其他自定义message类型。
2.2 给字段赋值数字标签
从上例中可以发现,message中定义的每个字段都有一个唯一的数字标签。该标签的作用是在二进制message中唯一标示该字段,一旦定义该字段的值就不能够再更改。有一点需要强调:1~15的数字标签编码后仅占一个字节(byte),包括数字标签和字段类型。16~2047的数字标签占两个字节(byte)。因此,1~15的数字标签应该用于最频繁出现的元素。设计时要考虑到不要一次用完1~15的标签,要考虑到将来也可能出现频繁出现的元素。
最小的数字标签是1,最大的数字标签是2的29次方-1,也即 536,870,911。但是并不是这之间所有的数字标签你都能用,例如19000~19999。这个区间的数字标签就像是java中的保留字一样,他们是PB的保留数字标签。如果该区间的数字标签出现在.proto文件中,PB编译器会出错。
2.3 字段标示符
字段标示符有三个:
message的没一个字段,都要用如下的三个修饰符(modifier)来声明:
required:必须赋值,不能为空,否则该条message会被认为是“uninitialized”。build一个“uninitialized” message会抛出一个RuntimeException异常,解析一条“uninitialized” message会抛出一条IOException异常。除此之外,“required”字段跟“optional”字段并无差别。
optional:字段可以赋值,也可以不赋值。假如没有赋值的话,会被赋上默认值。对于简单类型,默认值可以自己设定,例如上例的PhoneNumber中的PhoneType字段。如果没有自行设定,会被赋上一个系统默认值,数字类型会被赋为0,String类型会被赋为空字符串,bool类型会被赋为false。对于内置的message,默认值为该message的默认实例或者原型,即其内所有字段均为设置。当获取没有显式设置值的optional字段的值时,就会返回该字段的默认值。
repeated:该字段可以重复任意次数,包括0次。重复数据的顺序将会保存在protocol buffer中,将这个字段想象成一个可以自动设置size的数组就可以了。
由于一些历史原因,数字类型的repeated字段性能有些不尽人意,但是,PB已经做了改进,但是需要再添加一点改动,即在声明后添加[packed=true]例如:
?
1
repeated int32 samples = 4 [packed=true];
Notice:应该格外小心定义Required字段。当因为某原因要把Required字段改为Optional字段是,会有问题,老版本读取器会认为消息中没有该字段不完整,可能会拒绝或者丢弃该字段(Google文档是这么说的,但是我试了一下,将required的改为optional的,再用原来required时候的解析代码去读,如果字段赋值的话,并不会出错,但是如果字段未赋值,会报这样错误:Exception in thread “main” com.google.protobuf.InvalidProtocolBufferException: Message missing required fields:fieldname)。在设计时,尽量将这种验证放在应用程序端的完成。Google的一些工程师对此也很困惑,他们觉得,required类型坏处大于好处,应该尽量仅适用optional或者repeated的。但也并不是所有的人都这么想。
2.4 同一.proto文件定义多个message
PB支持同一.proto文件定义多个message。这在需要定义相关message的时候非常有用,例如:除了搜索请求message,还需要定义搜索响应message,可以再同一.proto文件中定义:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
message SearchRequest {
required string query = 1;
optional int32 page_number = 2;
optional int32 result_per_page = 3;
}
message SearchResponse {
...
}
2.5 添加评论
使用C/C++风格的注释 // syntax,如下例子:
?
1
2
3
4
5
6
7
8
9
message SearchRequest {
required string query = 1;
optional int32 page_number = 2;// Which page number do we want?
optional int32 result_per_page = 3;// Number of results to return per page.
}
2.6 编译.proto文件后产生了什么?
用PB 编译器运行.proto文件后,会按照定义的格式,生成指定语言的一系列代买,这些代码的功能包括:字段值的getter,setter,序列化message并写入到输出流,从输入流接写成message等。
对于Java,编译器生成一个.java文件,该java文件内包含几个内部类,分别对应.proto文件中定义的message 类型,以及将来用于创建message类实例的Builder类。
3. 标准值类型
.proto Type Notes C++ Type Java Type Python Type[2]
double double double float
float float float float
int32 使用可变长编码. 对于负数比较低效,如果负数较多,请使用sint32 int32 int int
int64 使用可变长编码. 对于负数比较低效,如果负数较多,请使用sint64 int64 long int/long
uint32 使用可变长编码 uint32 int
int/long
uint64 使用可变长编码 uint64 long
int/long
sint32 使用可变长编码. Signed int value. 编码负数比int32更高效 int32 int int
sint64 使用可变长编码. Signed int value. 编码负数比int64更高效 int64 long int/long
fixed32 恒定四个字节。如果数值几乎总是大于2的28次方,该类型比unit32更高效。 uint32 int
int
fixed64 恒定四个字节。如果数值几乎总是大于2的56次方,该类型比unit64更高效。 uint64 long
int/long
sfixed32 恒定四个字节 int32 int int
sfixed64 恒定八个字节 int64 long int/long
bool bool boolean boolean
string A string must always contain UTF-8 encoded or 7-bit ASCII text. string String str/unicode
bytes 包含任意数量顺序的字节 string ByteString str
4. Optional字段及其默认值
上面提到,PB允许设置可选字段(optional)。顾名思义,在一条message中,该字段可设值也可不设。假如没有设置,那么在解析该字段的时候,会根据该字段类型,给其赋一个类型默认值。除此之外,也可以在定义message格式的时候,就为optional字段设置一个默认值,如下:
?
1
optional int32 result_per_page = 3 [default = 10];
假如没有赋值的话,会被赋上默认值。对于简单类型,默认值可以自己设定,例如上例的PhoneNumber中的PhoneType字段。如果没有自行设定,会被赋上一个系统默认值,数字类型会被赋为0,String类型会被赋为空字符串,bool类型会被赋为false。对于枚举类型,默认值是枚举列表中第一个值。
5. 枚举类型
在定义message类型的时候,也许会有这样一种需求:其中的一个字段仅需要包含预定义的若干个值即可。比如,对于每一个搜索请求,现需要增加一个分类字段,分类包含:UNIVERSAL, WEB, IMAGES, LOCAL, NEWS, PRODUCTS or VIDEO。要实现该功能,仅需要增加一个枚举类型字段。如下:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
message SearchRequest {
required string query = 1;
optional int32 page_number = 2;
optional int32 result_per_page = 3 [default = 10];
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
optional Corpus corpus = 4 [default = UNIVERSAL];
}
还可以给枚举值设置别名,仅需将相同的数字标签设置给不同的名称即可。这里,必须得设置allow_alias为true,否则PB编译器会报错。
?
1
2
3
4
5
6
7
8
9
10
11
12
enum EnumAllowingAlias {
option allow_alias = true;
UNKNOWN = 0;
STARTED = 1;
RUNNING = 1;
}
enum EnumNotAllowingAlias {
UNKNOWN = 0;
STARTED = 1;
// RUNNING = 1; // Uncommenting this line will cause a compile error inside Google and a warning message outside.
}
可以定义枚举在一个message内部,如上例。也可以定义在message的外部,这样的枚举可以被其他任何.proto文件内的message复用。
6. 使用其他Message类型作为filed类型
PB允许使用message类型作为filed类型。例如,在搜索相应message中,包含一个结果message。此时,只需要定义一个结果message,然后再.proto文件中,在搜索结果message中新增一个字段,该字段的类型设置为结果message即可。如下:
?
1
2
3
4
5
6
7
8
9
message SearchResponse {
repeated Result result = 1;
}
message Result {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
6.1 导入定义
在上例中,Result message类型与SearchResponse 定义在同一个文件中,假如有这么一种情况,这里所要使用的Resultmessage已经在其他的.proto文件中定义了呢?
可以通过导入其他.proto文件来使用其内的定义。为达此目的,需要在现.proto文件前增加一条import语句:
?
1
import "myproject/other_protos.proto";
7. 嵌套类型
PB支持message内嵌套message,如下例子中,Result message 定义在了SearchResponse内:
?
1
2
3
4
5
6
7
8
message SearchResponse {
message Result {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
repeated Result result = 1;
}
如果想要在父Message外复用该message的话,可以用Parent.Type格式来引用。
?
1
2
3
message SomeOtherMessage {
optional SearchResponse.Result result = 1;
}
PB支持无限深层次的message嵌套:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
message Outer { // Level 0
message MiddleAA { // Level 1
message Inner { // Level 2
required int64 ival = 1;
optional bool booly = 2;
}
}
message MiddleBB { // Level 1
message Inner { // Level 2
required int32 ival = 1;
optional bool booly = 2;
}
}
}
8. 更新Message类型
如果现有message类型不能在满足业务需求,例如,需要新增一个字段,但是我们却希望依然能够使用原来的.proto生成的代码。完全没有问题,仅需记住如下规则:
千万不要修改现有字段后边的数值标签
只能新增optional或者repeated字段
可以删除非必须字段,但是他们的数字标签不能再被使用。最好的方法是不删除,而是修改名字,比如在前缀上加OBSOLETE_,这样就可以避免后人尽量少的出错。
非required字段可以转化成extension字段,反之亦然,同时保留原类型和数字标签
int32, uint32, int64, uint64, 和bool是兼容的。即这些字段可以相互切换,在代码处理的时候,不会出错,但是小心范围小的数据接收范围大的数据会发生截断
sint32, sint64是相互兼容的,但是不与其他整型类型兼容
string和bytes是兼容的,因为bytes也是合法的UTF-8
Embedded messages are compatible with bytes if the bytes contain an encoded version of the message(不知道怎么翻译了)
fixed32与 sfixed32兼容, fixed64 与sfixed64兼容
optional与repeated兼容,也存在数据截断,假如讲一个repeated的序列化后的数据作为输入给客户端,客户端会截取最后一个原子类型的字节。或者,如果是一个message类型的字段的话,合并所有的元素。
可以修改字段默认值
9. Package
PB建议在.proto文件开头添加一个package说明符来避免不同message类型的名字冲突:
?
1
2
3
package foo.bar;
message Open { ... }
这样,就可以使用该package标示符来定义该message类型的字段:
?
1
2
3
4
5
6
7
8
9
message Foo {
...
required foo.bar.Open open = 1;
...
}
不同语言,因为添加package标示符,生成的代码也会有所不同,Java中,该package将会被用作java文件的package。如果不想这样的话,也可在.proto文件中显式指明package,该字段是:java_package。
译自:https://developers.google.com/protocol-buffers/docs/proto
发表评论
-
netty4更新详解
2015-11-14 10:52 641netty现在应该是java界最流行的网络框架之一了,高性能, ... -
Lua使用protocolbuf
2015-11-10 16:04 869在https://code.google.com/p/prot ... -
领域模型设计
2015-09-12 17:29 692一:面向对象设计中最简单的部分与最难的部分 如果说事务脚本是 ... -
关于分表与分库思路
2015-07-06 15:36 628首先主要实现应该参考开源产品,目前比较能上台面的是 tddl, ... -
NAT穿透解决方案介绍
2015-04-01 03:12 2008最近公司要实现在各种网络环境下面的多屏互动(机顶盒、andro ... -
音视频即时通讯开发中使用P2P技术的好处
2015-04-01 02:59 745在服务器的配置文件“A ... -
nat穿透原理
2015-04-01 02:01 1055一直以来,说起NAT穿透,很多人都会被告知使用UDP打孔这个技 ... -
Erlang学习记录(二)——基本数据类型
2015-03-30 03:51 474Erlang学习记录(二)—— ... -
集群、分布式、负载均衡区别与联系
2015-03-25 22:54 5941、Linux集群主要分成三 ... -
: 结构化数据的共享存储
2015-03-24 04:25 0开发笔记 (6) : 结构化数据的共享存储 开始这个话题前, ... -
:如何构建超强伸缩性的游戏服务器而集容错、负载均衡和无限伸缩性于一身
2015-03-24 04:04 913附标题:如何构建超强 ... -
edis在游戏服务器中的应用
2015-03-24 02:57 624edis在游戏服务器中的应 ... -
社交游戏之双机热备方案 预防单点故障
2015-03-23 04:46 882某一天深夜,单盘配置的服务器出现硬盘损坏,导致该服务器上所提 ... -
游戏服务器集群设计思路
2015-03-23 04:45 797对于我们的游戏服务器端来说,除了要满足一般的MMO服务 ... -
Erlang类型及函数声明规格
2015-03-04 14:33 663Erlang类型及函数声明规格 Author: Mail: ... -
(转)erlang lists模块函数使用大全
2015-02-12 16:26 629一,带函数Pred 1, all(Pred ... -
超越并行框架erlang之流的通讯框架
2015-02-05 17:41 653http://blog.codingnow.com/2011/ ... -
如何使用 Oracle Linux 中的硬件故障管理
2014-11-10 14:38 1474如何使用 Oracle Linux 中 ... -
配置nginx
2014-06-14 18:04 614http://www.cnblogs.com/wenanry/ ... -
centos 安装mysql
2014-06-13 12:23 600你是root權限嗎?_操作系統的_ 兩種方法 1 使用替換法 ...
相关推荐
Protocol Buffers 语法指南 Protocol Buffers(简称 PB)是一种语言无关、平台无关、可扩展的序列化数据格式,由 Google 开发。PB 语法指南是指在使用 Protocol Buffers 时需要遵守的语法规则。本文将详细介绍 PB ...
Protocol Buffers是由Google开发的一种高效、灵活的数据序列化机制,旨在替代XML和其他传统序列化方式。...要了解更多细节,可以参考Protocol Buffer编码指南和API参考文档,以及关于编写.proto文件的语言指南。
"PPT]Google Protocol Buffers.pdf"是官方的Protocol Buffers文档,其中包含了详细的使用指南、API参考和最佳实践。对于开发者来说,这是一个非常重要的资源,可以帮助他们理解如何设计和使用Protocol Buffers,以及...
本指南为Google的Protocol Buffers语言指南,它描述了如何使用Protocol Buffers协议来构建你的数据结构,涵盖了.proto文件语法以及如何从.proto文件生成数据访问类。此指南主要介绍的是proto2版本的Protocol Buffers...
标题“Protobuf-Delphi”指的是一个针对Delphi开发环境定制的Protocol Buffers实现。Protocol Buffers是由Google开发的一种数据序列化协议,它允许开发者定义数据结构,然后生成能够在多种编程语言之间无缝交换数据...
“google protoc-2.5.win”是Google Protocol Buffers(简称protobuf)的编译器,版本为2.5,针对Windows平台。Protocol Buffers是一种数据序列化协议,它可以将结构化数据序列化,可用于数据存储、通信协议等方面。...
1. `.proto` 文件:这些文件用Protocol Buffer语法编写,定义了服务接口、消息类型和数据结构。开发者可以通过编译.proto文件生成对应语言(如Python)的SDK,以便在代码中调用和实现这些接口。 2. `setup.py`:...
标题中的"window版本的protoc"指的是Google开源的Protocol Buffers(简称protobuf)编译器在Windows操作系统上的实现。Protocol Buffers是一种数据序列化协议,它允许开发者定义数据结构,然后生成能够在各种编程...
"grpc-scala-sample"是一个项目,它基于Java的gRPC框架,并使用ScalaPB(Scala Protocol Buffers)进行了移植。这里的关键词是gRPC、ScalaPB和Protocol Buffers,它们是这个项目的核心技术栈。 【gRPC】 gRPC是一个...
.proto文件是Google开源的Protocol Buffers(简称Protobuf)使用的定义数据结构的语法文件。Protobuf是一种高效的数据序列化协议,类似于XML和JSON,但更小、更快、更简单。它允许开发者定义数据结构,然后生成能够...
标题中的"protobuf.rar"表明这是一个关于Protocol Buffers(通常简称为Protobuf)的压缩文件,它是一个高效的数据序列化协议,由Google开发并开源。这个压缩包可能包含了不同版本的Protobuf编译器,即protoc,以及一...
标题 "protoc-2.4.1-win32" 指的是Google开源的Protocol Buffers(简称protobuf)编译器的一个特定版本,用于Windows 32位操作系统。Protocol Buffers是一种高效的数据序列化协议,它允许开发者定义数据结构,然后...
gRPC使用Protocol Buffers作为其接口描述语言,以定义服务和消息格式。 rpcx是一个Go语言编写的分布式全功能RPC框架。它构建于gRPC之上,能够实现高可用性和高并发的分布式系统。rpcx支持多种插件,可以进行服务...
在描述中提到的“官网地址:https://github.com/protocolbuffers/protobuf/releases”,这是protobuf项目的官方GitHub仓库,用户可以在该页面找到protobuf的所有发布版本,包括源代码、预编译的二进制文件以及相关...
标题中的"protobuf-all-3.11.4.tar.gz"是一个开源软件库的归档文件,其中包含了Protocol Buffers(protobuf)的版本3.11.4的所有组件。Protocol Buffers是Google开发的一种数据序列化协议,它允许结构化数据进行串行...
protobuf-python-3.17.3 是一个针对Python编程语言的Protocol Buffers(简称protobuf)版本,主要用于数据序列化。Protocol Buffers是Google开发的一种高效、灵活的数据序列化格式,可与XML、JSON等格式互换,但通常...
protobuf开发指南旨在帮助开发者了解和使用Google的Protocol Buffers(简称PB),这是一种高效、语言中立、平台中立的结构化数据序列化方法。PB在数据存储和通信协议中广泛应用于Google内部。与XML相比,protobuf...
标题 "protobuf-2.4.1.zip" 指向的是 Protocol Buffers(简称protobuf)的一个版本2.4.1的归档文件。Protocol Buffers是Google开发的一种数据序列化协议,它允许开发者定义数据结构,然后生成能够在各种数据平台之间...
标题中的"protoc-3.9.1-win64.zip"指的是Protocol Buffers(简称protobuf)的编译器protoc的Windows 64位版本3.9.1的压缩包。Protocol Buffers是Google开发的一种数据序列化协议,用于结构化数据的序列化,类似于XML...
标题中的"protoc-2.5.0 windows平台"指的是Protocol Buffers(通常简称为protobuf)的编译器protoc的2.5.0版本,适用于Windows操作系统。Protocol Buffers是Google开发的一种数据序列化协议,它允许开发者定义数据...