文档章节

protobuf 语法浅析

hgfgoodcreate
 hgfgoodcreate
发布于 2016/07/16 10:40
字数 2157
阅读 708
收藏 0

精选30+云产品,助力企业轻松上云!>>>

Protobuf

为什么用Protobuf Buffer

跨语言平台编程,使用SOAP的话,该方式是使用xml的方式传输,会大大增加网络的IO,而且xml的解析复杂,降低报文的解析性能。

定义一个Protobuf消息

message LogonReqMessage{
	required int64 actID=1;
	required string passwd=2;
}

关键说明:

  1. message是消息的关键字
  2. LogonReqMessage是消息名字,相当于java的类名
  3. required前缀表示该字段未必要字段,序列化前后必须赋值的字段。protobuf还存在两个类似的关键字optionalrepeated主要用于表示数组字段。
  4. int64和string表示长整型和字符串类型的消息字段,在protobuf中存在一张类型对照表,即protobuf类型与其他语言的类型对照。
  5. actID和passwd分别表示消息的字段名,等同于java中的域名变量名。
  6. 标签数字12表示不同的字段在序列化前后的二进制中的布局位置。在本例中,passwd字段编码后的数据一定位于actID后,该值在同一个message中不能重复。对于protobuf而言,标签1到15的字段在编码的时候是可以得到优化的(标签值和类型信息只占一个byte,标签范围16到2047占两个byte),protobuf可支持的字段数量是$2^{29}-1$。因此,应该将repeated类型的字段标签未与1~15,节省编码后的字节数量。

定义第二个protobuf消息

enum UserStatus{
	OFFLINE=0;
	ONLINE=1;
}

message UserInfo{
	required int64 actID=1;
	required string name=2;
	required UserStatus=3;
}

关键说明:

  1. enum是枚举类型的关键字,等同于java里面的enum
  2. UserStatus为枚举的名字
  3. 和java一样枚举之间的分隔符是分好;而不是逗号,
  4. OFFLINEONLINE表示枚举值
  5. 01表示枚举所对应的实际整型值,可为任意整型值,无需从0开始。

定义第三个protobuf消息

enum UserStatus{
	OFFLINE=0;
	ONLINE=1;
}

message UserInfo{
	required int64 actID=1;
	required string name=2;
	required UserStatus=3;
}

message LogonRespMessage{
	required LoginResult logonResult = 1;
	required UserInfo userInfo = 2;
}

关键说明:

  1. LogonRespMessage消息定义中包含另外一个消息类型作为其字段,如UserInfo userInfo
  2. 上例的UserInfo和LogonRespMessage被定义在同一个.proto文件中,那么怎么包含其他proto文件中的message呢?ProtoBuf提供关键字import将其他proto文件的message引入到当前proto文件中。例如Import "myproject/CommonMessages.proto"

限定符号

  1. 每个消息必须有一个字段是required类型的字段。
  2. 每个消息包含0个或多个optional类型的字段。
  3. repeated表示的字段可以包含0个或多个数据,有别于java的数组,因为java数组中至少包含一个元素
  4. 如果打算在原有消息协议中添加新的字段,同时保证老的字段能正常的读取写入,那么新添加的字段必须是optional或者repeated类型的。

proto类型对照表

.proto Type Notes C++ Type Java Type
double double double
float float float
int32 "Uses variable-length encoding. Inefficient for encoding negative numbers ¨C if your field is likely to have negative values use sint32 instead." int32 int
int64 "Uses variable-length encoding. Inefficient for encoding negative numbers ¨C if your field is likely to have negative values use sint64 instead." int64 long
uint32 Uses variable-length encoding. uint32 int
uint64 Uses variable-length encoding. uint64 long
sint32 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. int32 int
sint64 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. int64 long
fixed32 Always four bytes. More efficient than uint32 if values are often greater than 228. uint32 int
fixed64 Always eight bytes. More efficient than uint64 if values are often greater than 256. uint64 long
sfixed32 Always four bytes. int32 int
sfixed64 Always eight bytes. int64 long
bool bool boolean
string A string must always contain UTF-8 encoded or 7-bit ASCII text. string String
bytes May contain any arbitrary sequence of bytes. string ByteString

protobuf消息升级原则

  1. 不要修改已经存在字段的标签号
  2. 任何新添加的字段必须是optional或者repeated限定符,否则无法保证新老程序在互传消息的时候消息的兼容性。
  3. 在原有消息中,不能移除已经存在的required字段,optionalrepeated类型字段可以移除,但是他们之前使用的标签不能使用了。
  4. int32uint32int64uint64bool等类型之间是兼容的,sint32sint64是兼容的,stirngbyte是兼容的,fixed32sfixed32是兼容的,fixed64sfixed64是兼容的,如果想修改原有字段类型,为了保证兼容性,只能将其修改为原有类型兼容的类型,否则打破新老消息格式的兼容性。
  5. optionalrepeated限定符是相互兼容的。

packages

可以在.proto文件中定义包名,如:package abc.lypgone,该包名生成c++时,替换成名字空间,而java为java的包名。

options

protobuf 在.proto文件中定义一些常用的选项,这样protobuf可以帮助我们生成更匹配的目标语言代码。

protobuf的内置选项分为三个等级:

  1. 文件级,这样的选项影响当前文件的所有消息和枚举。
  2. 消息级,这样的选项仅影响某个消息及其包含的所有字段。
  3. 字段级,这样的选项近影响某个字段。

常用的protobuf选项有:

  1. option java_package="com.companyname.projectname"; java_package 是文件级的选项,指定让生成的java代码的包名为该选项的值;与此同时,输出的文件也自动输出到对应包目录下(上例的com/companyname/projectname目录下),该选项对C++没有影响。
  2. option java_outer_classname="LYPhoneMessage"; java_outer_classname是文件级别的选项,指定生成的java代码的外部类名称。如果没有指定,java代码的外部类名称为当前文件的文件名部分,同时将文件名转为驼峰格式,如my_project.proto,那么该文件的外部类名为MyProject,该选项对C++代码无影响。

注意,由于一个java文件只能有一个外部类或者外部接口,所以.proto文件中的message定义的消息均为外部类的内部类,这样才能将这些消息定义到一个文件中。c++没有此限制。

  1. option optimize_for = LITE_RUNTIME; optimize_for 是文件级选项,是protobuf优化选项。该选项又分为3个等级:
    1. SPEED:表示生成的代码运行效率高,但是由此生成的代码编译后会占用更多的空间
    2. CODE_SIZE: 和SPEED恰恰相反,代码运行效率较低,但是由此生成的代码编译后会占用更少的空间,通常用于资源有限的平台,如Mobile。
    3. LITE_RUNTIME: 生成的代码执行效率高,同时生成代码编译后的所占用的空间也是非常少。这是以牺牲Protocol Buffer提供的反射功能为代价的。因此我们在C++中链接Protocol Buffer库时仅需链接libprotobuf-lite,而非libprotobuf。在Java中仅需包含protobuf-java-2.4.1-lite.jar,而非protobuf-java-2.4.1.jar

对于LITE_MESSAGE选项而言,其生成的代码均将继承自MessageLite,而非Message

  1. [pack = true]: 因为历史原因,对于数值型的repeated字段,如int32、int64等,在编码时并没有得到很好的优化,然而在新近版本的Protocol Buffer中,可通过添加[pack=true]的字段选项,以通知Protocol Buffer在为该类型的消息对象编码时更加高效。如:repeated int32 samples = 4 [packed=true]

注:该选项仅适用于2.3.0以上的Protocol Buffer

  1. [default = default_value]: optional类型的字段,如果在序列化时没有被设置,或者是老版本的消息中根本不存在该字段,那么在反序列化该类型的消息是,optional的字段将被赋予类型相关的缺省值,如bool被设置为false,int32被设置为0。Protocol Buffer也支持自定义的缺省值,如:optional int32 result_per_page = 3 [default = 10]。

命令行编译工具

protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR path/to/file.proto

这里将给出上述命令的参数解释。

  1. protoc为Protocol Buffer提供的命令行编译工具
  2. --proto_path等同于-I选项,主要用于指定待编译的.proto消息定义文件所在的目录,该选项可以被同时指定多个。
  3. --cpp_out选项表示生成C++代码--java_out表示生成Java代码--python_out则表示生成Python代码,其后的目录为生成后的代码所存放的目录。
  4. path/to/file.proto表示待编译的消息定义文件

注:对于C++而言,通过Protocol Buffer编译工具,可以将每个.proto文件生成出一对.h和.cc的C++代码文件。生成后的文件可以直接加载到应用程序所在的工程项目中。如:MyMessage.proto生成的文件为MyMessage.pb.h和MyMessage.pb.cc。

上一篇: git 常用总结
hgfgoodcreate
粉丝 16
博文 76
码字总数 162954
作品 0
海淀
程序员
私信 提问
加载中
请先登录后再评论。
Google Protobuf入门与使用

[toc] Google Protobuf入门与使用 Protobuf是Google的编解码技术,在业界十分流行,通过代码生成工具可以生成不同语言版本的源代码。 Protobuf代码生成工具与使用 protobuf下载 访问Google的...

xpleaf
2018/02/15
0
0
golang Protobuf学习

   protobuf是一种高效的数据传输格式(Google's data interchange format),且与语言无关,protobuf和json是基于http服务中最常见的两种数据格式。今天来学习基于golang的protobuf相关内...

暮色伊人
2018/01/26
0
0
Derek解读Bytom源码-protobuf生成比原核心代码

作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockchain/bytom 本章介绍bytom代码Api-Server接口服务 作者使用MacOS操作系统,其他平台...

比原链Bytom
2018/08/23
0
0
Golang语言下使用Protocol Buffer教程

代码仓库地址 一、介绍 Protobuf是Google旗下的一款平台无关,语言无关,可扩展的序列化结构数据格式。所以很适合用做数据存储和作为不同应用,不同语言之间相互通信的数据交换格式,只要实现...

Zoctopus_Zhang
2018/08/13
0
0
Golang语言下使用Protocol Buffer教程

代码仓库地址 一、介绍 Protobuf是Google旗下的一款平台无关,语言无关,可扩展的序列化结构数据格式。所以很适合用做数据存储和作为不同应用,不同语言之间相互通信的数据交换格式,只要实现...

osc_vxlxmpgv
2018/08/13
1
0

没有更多内容

加载失败,请刷新页面

加载更多

如何妙用Spring 数据绑定机制

前言 在剖析完 Spring Boot 返回统一数据格式是怎样实现的?文章之后,一直觉得有必要说明一下 Spring's Data Binding Mechanism 「Spring 数据绑定机制」。 默认情况下,Spring 只知道如何转...

码农小胖哥
2019/12/27
9
0
动态规划:LC70.爬楼梯

题目描述: 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数。 思路: 还是三部曲: 1.定义数组...

曦鱼violet
昨天
17
0
Linux Centos 7 - MySQL 5.7 在线安装

环境搭建:https://my.oschina.net/discussjava/blog/4308730 一、环境 Centos 7 MySQL 5.7 二、安装与配置 2.1 查询并卸载系统自带的 Mariadb 原因:以前的Linux系统中数据库大部分是mysql...

华山猛男
昨天
15
0
类似吾爱破解论坛的网站有哪些?破解软件网站合集推荐

17软件下载 这个网站呢楼主一直作为镜像下载网站在用,无论是最新的windows系统、office、还有其他专业软件都可以找到最新的软件下载,而且作为下载站居然没有推广软件和弹窗,简直良心,强烈...

树懒宝宝
昨天
34
0
Eclipse,Subclipse和Subversive的SVN插件的优缺点是什么? [关闭]

问题: SVN in Eclipse is spread into two camps. Eclipse中的SVN分为两个阵营。 The SVN people have developed a plugin called Subclipse . SVN人开发了一个名为Subclipse的插件。 The ......

技术盛宴
昨天
25
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部