文档章节

protobuf 语法浅析

hgfgoodcreate
 hgfgoodcreate
发布于 2016/07/16 10:40
字数 2157
阅读 321
收藏 0
点赞 0
评论 0

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。

© 著作权归作者所有

共有 人打赏支持
hgfgoodcreate
粉丝 8
博文 51
码字总数 117746
作品 0
海淀
程序员
grpc| python 实战 grpc

date: 2018-5-15 22:12:32 title: grpc| python 实战 grpc description: 只要代码可以跑起来, 很多难题都会迎刃而解. so, keep coding and stay hungry. 之前用 swoole 写 server 时就接触过...

daydaygo
05/16
0
0
Notepad++ 的 protobuf 高亮显示和列表显示

项目地址: https://github.com/chai2010/notepadplus-protobuf

chai2010
2015/07/29
0
0
Google Protobuf 开发指南

Google Protobuf开发指南 1.简介 l 它是开源项目:http://code.google.com/p/protobuf/ l 由google开发,并且在google内部使用 l Protobuf的作用和xml、json是一回事,但他是二进制格式,性能...

macwe
2013/08/29
0
1
Centos6.4下安装protobuf及简单使用

1、protobuf是google公司提出的数据存储格式,详细介绍可以参考:https://code.google.com/p/protobuf/ 2、下载最新的protobuf,下载地址:https://code.google.com/p/protobuf/downloads/li...

天下杰论
2015/05/09
0
0
我的Protobuf消息设计原则(续)--实践

1.首先为 聊天服务器(Chat)定义google protobuf的协议接口文件 接口主要遵循 Request、Response、Notification(Indication),Command(本文未出现)四大消息分类,并且使用Message顶层消...

newzai
2014/07/19
0
19
基于Go语言的protobuf 安装 以及简单测试用例

先去官网下载protobuf的源码 https://github.com/google/protobuf/releases 可以先下载本地,然后上传到虚拟机中 我选择的是Source code(tar.gz) 安装依赖包(如果缺少包,可能会报错) yum i...

故新
07/04
0
0
开源点评:Protocol Buffers介绍

今天来介绍一下“Protocol Buffers”(以下简称protobuf)这个玩意儿。本来俺在构思“生产者/消费者模式 ”系列的下一个帖子:关于生产者和消费者之间的数据传输格式。由于里面扯到了protobu...

彭苏云
2014/09/26
0
0
protobuf 2.5.0 编译jar

本机是windows环境 1. 下载 protobuf最新版本:https://code.google.com/p/protobuf/downloads/detail?name=protobuf-2.5.0.tar.gz 2. 解压后发现没有包.java下面只有一个POM.xml. 用maven吧.......

山海经
2014/05/17
0
0
几种序列化协议(protobuf,xstream,jackjson,jdk,hessian)相关数据

别人的相关测试数据: http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking 测试纬度 序列化时间 反序列化时间 bytes大小 测试代码 准备protobuf文件 Message.proto文件代码...

SANSOM
2015/08/20
0
0
google的protobuf库

这篇文章将讲述如何使用google的protobuf库实现一个RPC service,就实现一个最简单的service吧:echo.文章对应的代码都可以在eventrpc中找到,写下这篇文章时的svn revision是138. 1) 定义协议首...

moki_oschina
06/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

shell及python脚本方式登录服务器

一、问题 在工作过程中,经常会遇见需要登录服务器,并且因为安全的原因,需要使用交互的方式登录,而且shell、python在工作中也经常用到,并且可以提供交互的功能。都是利用了expect、spawn...

yangjianzhou
10分钟前
0
0
upstream sent too big header while reading...

nginx 报错:1736 upstream sent too big header while reading response header from upstream 1. 一般处理 location ~ \.php$ { #增加下面两句 fastcgi_buffer_size 128k; ......

dubox
20分钟前
0
0
Python解析配置文件模块:ConfigPhaser

import configparser as pa# [SectionA]# a = aa# b = bb# c = cc# [SectionB]# optionint = 1# optionfloat = 1.1# optionstring = string#https://www.cnblogs.com/a......

易野
27分钟前
0
0
Java基础——面向对象

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 Object的方法: clone() Object 克隆 to Strin...

凯哥学堂
29分钟前
0
0
rabbitmq学习记录(八)消息发布确认机制

RabbitMQ服务器崩了导致的消息数据丢失,已经持久化的消息数据我们可以通过消息持久化来预防。但是,如果消息从生产者发送到vhosts过程中出现了问题,持久化消息数据的方案就无效了。 Rabbit...

人觉非常君
33分钟前
0
0
毕业5年,我是怎么成为年薪30W的运维工程师

#转载# 我在大学读的是计算机专业,但大学毕业之后,进入到一家私企进行工作,工作的内容类似于网管,会经常的去修电脑,去做水晶头等内容。刚开始工作,也没想太多,最想的是丰富自己的工作...

Py爱好
40分钟前
1
0
大数据基础知识,大数据学习,涉及的知识点

一、什么是大数据 一种规模大到在获取、存储、管理、分析方面大大超出了传统数据库软件工具能力范围的数据集合,具有海量的数据规模、快速的数据流 转、多样的数据类型和价值密度低四大特征。...

董黎明
56分钟前
0
0
Linux CentOS 7上安装极点五笔

话说几天前在新买的惠普笔记本上成功地安装了Linux CentOS 7操作系统、Nvidia Quandro P600驱动程序及X Window,并在VMware下安装Red Hat教学环境,彻底跳出Windows的苦海,但仍然有一件事不...

大别阿郎
今天
17
0
2018年7月20日集群课程

一、集群介绍 集群,简单地说是指一组(若干个)相互独立的计算机,利用高速通信网络组成一个较大的计算机服务系统,每个集群节点(即集群中的每台计算机)都是运行各自服务的独立服务器。 ...

人在艹木中
今天
0
0
spark开发机中调试snappy

目的 在Idea中的点击运行,使spark可以直接读取snappy 自己编译hadoop,以支持snappy的压缩。 自己编译的目的就是要得到支持snappy文件读写的动态链接库。如果可以在网上下载,可以跳过自行编...

benny周
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部