Protocol Buffer技术详解(语言规范)
protobuf协议格式

protobuf协议格式摘要:1.引言2.protobuf协议简介3.protobuf协议的基本格式4.protobuf协议的优点5.protobuf协议在实际应用中的例子6.如何在Python中使用protobuf7.结论正文:**引言**在当今的软件开发中,数据交换格式的重要性不言而喻。
为了实现不同系统之间的数据互通,多种数据交换格式应运而生。
今天,我们将探讨一种在许多项目中广泛应用的协议——Protocol Buffers(简称protobuf)。
**protobuf协议简介**Protocol Buffers(简称protobuf)是一种轻量级的数据交换格式,由Google开发。
它是基于文本的,可以表示结构化数据。
与JSON、XML等格式相比,protobuf具有更小的体积和更高的解析速度。
它已经成为许多项目中的标配,尤其在分布式系统和嵌入式系统领域。
**protobuf协议的基本格式**一个简单的protobuf消息结构如下:```syntax = "proto3";message MyMessage {required int32 id = 1;required string name = 2;optional float price = 3;}```这里,`syntax`关键字定义了消息的版本。
`message`关键字定义了一个新的消息类型,后面的花括号中定义了消息的字段。
字段分为必需字段(required)和可选字段(optional)。
**protobuf协议的优点**1.紧凑的体积:与JSON、XML等格式相比,protobuf具有更小的体积,可以降低网络传输和存储的开销。
2.快速解析:protobuf使用二进制格式存储数据,解析速度较快。
3.易于扩展:protobuf消息结构灵活,可以轻松地添加或删除字段。
4.跨语言支持:protobuf具有良好的跨语言兼容性,几乎支持所有主流编程语言。
逆向还原protobuf结构-概述说明以及解释

逆向还原protobuf结构-概述说明以及解释1.引言1.1 概述概述部分:在现代软件开发中,Protobuf(Protocol Buffers)已经成为一种流行的数据序列化工具,被广泛应用于网络通信、数据存储以及日志记录等领域。
Protobuf结构简洁高效,能够实现跨语言的数据传输和存储,同时拥有良好的扩展性和兼容性。
本文将介绍逆向还原Protobuf结构的方法,通过分析Protobuf编译后的二进制数据,还原出原始的消息类型和字段结构。
我们将深入探讨如何解析Protobuf数据,理解字段类型和编码规则,并结合实际案例分析,帮助读者更好地理解和应用Protobuf技术。
通过本文的学习与实践,读者将能够更加深入地理解Protobuf的工作原理,提升对数据序列化与反序列化的理解水平,为自己在软件开发领域的技术能力提升提供有力支持。
1.2 文章结构文章结构部分主要是指整篇文章的组织架构和内容安排。
在本篇文章中,我们将按照以下方式进行内容的划分和组织:1. 引言部分:- 概述:介绍本文所要讨论的主题——逆向还原protobuf结构的背景和意义。
- 文章结构:介绍本文的整体组织结构,包括引言、正文和结论。
- 目的:明确本文的写作目的和预期效果。
2. 正文部分:- Protobuf简介:简要介绍Protobuf的基本概念和作用。
- 逆向还原Protobuf结构方法:详细介绍逆向还原Protobuf结构的具体方法和步骤。
- 实际应用和案例分析:通过实际的案例分析,说明逆向还原Protobuf结构在实际应用中的意义和作用。
3. 结论部分:- 总结:总结本文的主要观点和结论。
- 展望:展望未来逆向还原Protobuf结构的发展方向和可能的应用领域。
- 结束语:对整篇文章进行总结和回顾,强调文章的重要性和价值。
通过以上文章结构的安排,我们将能够清晰地向读者展示逆向还原protobuf结构的相关内容,使读者更加容易理解和掌握这一技术。
protobuf协议浅析

protobuf协议浅析协议名称:protobuf协议浅析一、引言protobuf协议是一种用于序列化结构化数据的语言无关、平台无关、可扩展的协议。
本文将对protobuf协议进行浅析,包括其定义、特点、使用场景以及优势等方面进行详细介绍。
二、定义protobuf协议全称为Protocol Buffers,它是一种由Google开发的数据序列化协议。
其基本思想是通过定义数据结构的消息格式,然后使用编译器生成相应的代码,以实现对数据的序列化和反序列化。
protobuf协议使用二进制格式进行数据传输,相比于XML和JSON等文本格式,具有更高的效率和更小的传输体积。
三、特点1. 简单性:protobuf协议使用简洁的语法定义消息结构,易于理解和使用。
2. 可扩展性:通过向消息结构中添加新的字段或消息类型,可以轻松扩展协议,而不会破坏已有的兼容性。
3. 语言无关性:protobuf协议支持多种编程语言,包括C++、Java、Python等,使得不同语言之间的数据交换更加便捷。
4. 性能优越:protobuf协议使用二进制格式进行数据传输,相比于文本格式,具有更高的效率和更小的传输体积。
5. 可读性:虽然protobuf协议使用二进制格式进行数据传输,但其提供了可读性较好的文本表示形式,方便调试和人工查看。
四、使用场景protobuf协议适用于以下场景:1. 分布式系统间的数据交换:protobuf协议可以在不同的分布式系统之间传递数据,实现数据的高效、可靠传输。
2. 跨平台数据传输:由于protobuf协议具有语言无关性,可以在不同的平台上使用不同的编程语言进行数据交换,如服务器与客户端之间的数据传输。
3. 数据存储与持久化:protobuf协议可以将数据序列化后存储在磁盘上,以实现数据的持久化存储和读取。
4. 网络通信协议:protobuf协议可以作为网络通信协议,用于实现不同节点之间的数据传输。
五、优势1. 效率高:protobuf协议使用二进制格式进行数据传输,相比于文本格式,传输效率更高。
ProtocolBuffers(Protobuf)官方文档--Protobuf语言指南

ProtocolBuffers(Protobuf)官⽅⽂档--Protobuf语⾔指南约定:为⽅便书写,ProtocolBuffers在下⽂中将已Protobuf代替。
本指南将向您描述如何使⽤protobuf定义i结构化Protobuf数据,包括.proto⽂件语法和如何使⽤.proto⽂件⽣成数据存取类。
作为⼀个参考指南,本⽂档将以⽰例的形式⼀步步向您介绍Protobuf的特点。
您可以参考您所选择的语⾔的⽰例。
--------------------------------------⼩⼩的分割线-----------------------------------------定义⼀个消息类型⾸先,看⼀个⾮常简单的例⼦,⽐如说你想定义⼀个搜索请求消息,每个搜索请求都有⼀个查询的字符串(关键字:⽐如我们上百度搜索《报告⽼板》),和我们搜索出来的⼀个感兴趣的⽹页,以及搜索到的所有⽹页总数。
来看看这个.proto⽂件是如何定义的。
1 message SearchRequest {2 required string query = 1;3 optional int32 page_number = 2;4 optional int32 result_per_page = 3;5 }这个"搜索请求"消息指定了三个字段(名称/属性组合),每⼀个你想要包含在这类型的信息内的东西,都必须有⼀个字段,每个字段有⼀个名称和类型!指定字段类型在上⾯的⽰例中,所有的字段都是标量类型():两个整数(integers:page_number和result_per_page)和⼀个字符串(string:query:查询的关键字),不过你可以在你的字段内指定符合类型。
包括枚举类型()和其他的消息类型分配指定标签号如你所见,每个消息的字段都有⼀个唯⼀的数字标签,这些标签⽤来表⽰你的字段在⼆进制消息()中处的位置。
一看看懂ProtocolBuffer(协议篇)

⼀看看懂ProtocolBuffer(协议篇)前⾔由于笔者业团队的业务对即时通讯服务有很⼤的依赖,春节结束后的第⼀天,红包没到,产品同学先到了,产品同学和我说要做⼀款IM,看到需求⽂档后和设计图后笔者⼤吃⼀⽄这不就是⼀个翻版的web qq吗?可以可以联想到最最近美团的⼤象,头条的Lark,⽤户与⽤户,商家与⽤户,企业同事的沟通,及其衍⽣的配套增值服务,真是需求旺盛的强需求啊如果我要做⼀个WebIM应⽤现在的Web应⽤通常会考虑ajax轮询或者是long polling的⽅式来实现,但是频繁的建⽴https连接,会带来多余请求和消息精准性的问题,本质上是TCP,消息边界不清晰,会有黏包的情况类似我司ios和andorid客户端,采⽤socket+PB协议来解决及时通讯问题,采⽤socket服务,依赖google的oc PB协议包来实现,socket是基于TCP协议,由通信协议和编程API组成的,原理⼀次HTTP协议握⼿成功后,与服务器建⽴双向连接,数据就可以直接从TCP 通道传输基于事件的⽅式,⼆级制传输,反编译为json或者xml笔者在查阅翻google PB开发者⽂档时,看到17年下半年google发布了官⽅的js的版本,配合websocket,可以与PB协议进⾏配合,在实现原理上,优于现有的ajax轮询或者是long polling的实现⽅式So,Let's rock !Protocol Buffer是个什么东东?Protocol Buffer是Google提供的⼀种数据序列化协议,下⾯是我从⽹上找到的Google官⽅对protobuf的定义:Protocol Buffers 是⼀种轻便⾼效的结构化数据存储格式,可以⽤于结构化数据序列化,很适合做数据存储或 RPC 数据交换格式。
它可⽤于通讯协议、数据存储等领域的语⾔⽆关、平台⽆关、可扩展的序列化结构数据格式。
为什么是Node,为何要和Protocol Buffer打交道?做为javascript开发者,对我们最好的数据序列化协议当然是JSON,pb协议相较于之前流⾏的XML更加的简洁⾼效pb属于⼆进制协议,更容易解析,解析速度⽐⽂本协议有⼆向箔级别的压制,so,在聊天场景下,udp传输明显是优于tcp的后台通信基本是基于⼆进制的,以往我们开发中⽤到的纯⽂本协议是后台同学在封装⼀层实现的,例如我司的服务,就维护了两套,⼀套⼆进制的,⼀套http接⼝的,如果可以⽤Node打通了pb,可以将维护成本降到最低,理论上只有⼀套底层⼆级制服务ps. 类似PB这样的东西,还有MessagePack和Apache Thrift说的这么热闹,⽼夫已经迫不及待了!想必你已经说,别逼逼,show me the code,怎么好的开发都么上进呢?好吧,Let's Rock & Roll!官⽅案例我们来操作⼀下安装google-protobuf2017年4⽉开始官⽅⽀持javascriptgithubdevelopsnpm install google1. -protobuf定义.proto⽂件proto⽂件 messages.proto1. package zxwj;2. syntax = "proto3";3. message helloworld4. {5. string zzuid = 123;6. string zzstatus = 0;7. }编译.proto⽂件使⽤protobuf.js命令⾏⼯具编译1. protoc --js_out=import_style=commonjs,binary:. messages.protoprotoc会编译输⼊⽂件,并且构建messages_pb,在sever中,可以以以下⽅式引⽤1. var messages = require('./messages_pb');2. var message = new messages.MyMessage();编写server.js1. var basepb = require('./messages_pb');2. console.log(basepb);3.4. var message = new basepb.SearchRequest();5. console.log(message);6.7. message.setName("TS");8. message.setPassword("123456");9.10. var bytes = message.serializeBinary(); //对象序列化11. console.log(bytes);12.13. var message2 = basepb.SearchRequest.deserializeBinary(bytes); //进制序列化14. console.log(message2);运⾏1. node sever.js总结⼀下上个案例并不具备线上产品能⼒,但是还可以能看出PB协议的优势所在快,从官⽅的测试结果来看,整体⽐較起來,ProtoBuf.js 則是⽐纯JSON 的处理快上⼀倍以上,附官⽅Github测试结果(机器配置:i7-2600K。
protobuf协议浅析

protobuf协议浅析协议名称:protobuf协议浅析一、介绍protobuf(Protocol Buffers)是一种轻量级的数据交换格式,由Google公司开发,用于结构化数据序列化。
它可以用于通信协议、数据存储等领域,具有高效、灵活、可扩展等特点。
二、协议格式protobuf协议使用.proto文件定义数据结构和消息格式。
一个.proto文件包含一个或多个message(消息)定义,每个message可以包含一个或多个字段。
每个字段有一个唯一的字段标识符和一个字段类型。
1. 字段类型protobuf支持多种字段类型,包括基本类型(如int、float、string等)、枚举类型、嵌套message类型等。
可以根据实际需求选择合适的字段类型。
2. 字段标识符每个字段有一个唯一的字段标识符,用于在序列化和反序列化过程中标识字段。
字段标识符是一个非负整数,取值范围为1~2^29-1。
在.proto文件中,可以为字段指定一个标识符,也可以使用默认的标识符。
3. 消息定义消息定义是.proto文件中最重要的部分,用于描述数据结构和消息格式。
每个消息定义由一个message关键字、一个消息名称和一对大括号组成。
在大括号中定义消息的字段。
三、协议使用使用protobuf协议需要进行以下步骤:1. 编写.proto文件根据实际需求,编写一个或多个.proto文件,定义数据结构和消息格式。
2. 编译.proto文件使用protobuf编译器将.proto文件编译成对应的编程语言文件。
protobuf支持多种编程语言,如C++、Java、Python等。
3. 序列化和反序列化在发送方,将数据序列化为protobuf格式,然后通过网络传输给接收方。
在接收方,将接收到的数据反序列化为原始数据。
4. 数据处理接收方可以根据消息定义中的字段标识符,对数据进行解析和处理。
四、优点和应用场景protobuf协议具有以下优点:1. 简洁高效:protobuf协议使用二进制编码,相比于文本格式,数据量更小,传输速度更快。
protobuf 语法基础
protobuf 语法基础protobuf是个特别酷的东西呢。
它就像是一种专门用来高效处理数据的小能手。
一、什么是protobuf。
protobuf全称Protocol Buffers,这名字听起来就很专业吧。
其实简单说呢,它就是一种轻便高效的结构化数据存储格式。
你想啊,在我们的程序世界里,数据就像一个个调皮的小精灵,到处跑到处窜。
而protobuf就像是给这些小精灵们建了一个个规规矩矩的小房子,让它们能整整齐齐地住进去,而且还能很方便地找到彼此。
比如说,我们有个游戏,里面有好多角色的信息,像角色的名字、等级、生命值啥的。
要是用普通的方式来存储和传输这些数据,可能就会变得乱糟糟的。
但是有了protobuf,就可以把这些数据按照一种清晰的结构组织起来。
就像给每个角色都做了一个精美的小档案夹一样。
二、protobuf的语法结构。
1. 消息定义。
这是protobuf里特别重要的一部分。
我们可以把消息想象成是一个装着各种数据的小盒子。
比如说,我们定义一个表示人的消息:message Person {required string name = 1;optional int32 age = 2;repeated string hobbies = 3;}这里面呢,“message”就是告诉protobuf我们要定义一个消息啦。
“Person”就是这个消息的名字。
然后下面的“required”“optional”“repeated”就像是给盒子里的东西贴的小标签。
“required”表示这个数据是必须有的,就像人的名字,没有名字怎么行呢?“optional”就是可有可无的啦,像年龄,有的人可能不想透露自己的年龄。
“repeated”就更有趣了,它表示这个数据可以有多个,就像爱好,一个人可以有好多个爱好呀。
后面的“string”“int32”就是说这个数据的类型啦,是字符串还是整数之类的。
“name = 1”“age = 2”“hobbies = 3”这些就是给每个数据元素一个独一无二的编号,这样protobuf就能准确地找到它们了。
Protocol Buffer入门
protobuf介绍按照官网的描述:protobuf是google提供的一个开源序列化框架。
主要应用于通信协议,数据存储中的结构化数据的序列化。
它类似于XML,JSON这样的数据表示语言,其最大的特点是基于二进制,因此比传统的XML表示高效短小得多。
虽然是二进制数据格式,但并没有因此变得复杂,开发人员通过按照一定的语法定义结构化的消息格式,然后送给命令行工具,工具将自动生成相关的类,可以支持java、c++、python等语言环境。
通过将这些类包含在项目中,可以很轻松的调用相关方法来完成业务消息的序列化与反序列化工作。
protobuf的优势1、语言中立2、平台中立3、高效性protobuf入门(eclipse下java环境的搭建)更多案例请查阅源代码包protobuf-2.3.0.zip 里面有关于各种支持语言(java,C++,python等)的案例。
1、下载jar包 protobuf-java-2.3.0.jar2、下载编译器protoc.exe3、新建java工程test_protobuf4、导入protobuf-java-2.3.0.jar包5、导入编译器protoc.exe到项目下6、在项目下建存放文件.proto的文件夹proto7、编写message并放在proto文件夹下,有关编写规范和说明请参考官网文档,在这里我引用官网的例子,创建addressbook.proto代码如下:package tutorial;option java_package = "com.example.tutorial";option java_outer_classname = "AddressBookProtos";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;}// Our address book file is just one of these.message AddressBook {repeated Person person = 1;}8、编译addressbook.proto成指定的java类命令行下进入编译器所在目录,执行如下命令protoc -I=proto/ --java_out=src proto/addressbook.proto其中,src为生成的java类的目标位置,这里我们选择项目的默认包,proto/addressbook.proto表示我们的proto文件,运行后即生成java类,生成的java类被放在了package com.example.tutorial中。
protobuf 编码原理
Protobuf编码原理1. 简介protobuf(Protocol Buffers)是一种用于结构化数据序列化的语言无关、平台无关、可扩展的机制。
它由Google开发,广泛应用于分布式系统中的数据通信和持久化存储。
protobuf定义了一种简洁的数据描述语言,通过这种语言可以定义数据结构的模式,然后使用编译器生成对应的代码,以便在不同的平台和语言间进行数据交换。
protobuf支持多种编程语言,如C++、Java、Python等。
protobuf的编码原理主要涉及到数据结构的定义、编码规则和编解码过程。
下面将详细介绍这些内容。
2. 数据结构定义在protobuf中,数据结构的定义通过.proto文件完成,这是一种文本文件,用于描述消息类型和字段。
一个.proto文件通常包含一个或多个message类型的定义。
每个message类型可以包含多个字段,每个字段都有一个唯一的标识号和一个类型。
标识号用于在编码和解码过程中标识字段,类型用于指定字段的数据类型。
protobuf支持的数据类型包括基本类型(如int、float、bool等)、字符串、嵌套message、枚举等。
下面是一个简单的.proto文件示例:syntax = "proto3";message Person {string name = 1;int32 age = 2;repeated string hobbies = 3;}在上述示例中,定义了一个名为Person的message类型,它包含三个字段:name、age和hobbies。
name字段的类型是字符串,age字段的类型是32位整数,hobbies字段的类型是字符串数组。
3. 编码规则protobuf使用一种紧凑、高效的编码规则将数据序列化为二进制格式。
这种编码规则被称为Varint编码和Length-Delimited编码。
3.1 Varint编码Varint编码用于对整数进行编码,它将一个整数按照变长编码的方式写入到字节流中。
protobuf协议浅析
protobuf协议浅析协议名称:protobuf协议浅析一、介绍protobuf(Protocol Buffers)是一种轻量级的数据交换格式,由Google开发并开源。
它使用二进制编码来序列化结构化数据,具有高效、简洁、可扩展的特点。
本协议旨在对protobuf协议进行浅析,介绍其基本概念、使用方法和优势。
二、基本概念1. 消息定义protobuf使用.proto文件来定义消息结构,包括消息名称和字段定义。
消息名称为唯一标识符,字段定义包括字段类型、字段名称和字段编号。
2. 字段类型protobuf支持多种字段类型,包括基本类型(如int、float、bool等)、枚举类型、嵌套消息类型和重复类型。
每个字段类型都有对应的标识符。
3. 字段编号每个字段都需要指定一个唯一的字段编号,用于序列化和反序列化时的标识。
字段编号只能是正整数,且不能重复。
4. 序列化和反序列化序列化是将结构化数据转换为二进制格式的过程,而反序列化是将二进制格式的数据转换为结构化数据的过程。
protobuf提供了相应的API来实现序列化和反序列化操作。
三、使用方法1. 安装protobuf首先,需要安装protobuf编译器,可以从Google的官方网站下载并按照说明进行安装。
2. 定义消息结构在.proto文件中定义消息结构,包括消息名称和字段定义。
可以使用嵌套消息类型来实现复杂的数据结构。
3. 编译.proto文件使用protobuf编译器将.proto文件编译为对应的编程语言文件,如C++、Java、Python等。
编译命令如下:protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR FILE.proto4. 序列化和反序列化在代码中使用protobuf提供的API进行序列化和反序列化操作。
可以将结构化数据转换为二进制格式,并将二进制格式转换为结构化数据。
5. 数据传输使用protobuf编码后的数据可以通过网络传输,或者存储到文件中。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
内容主体主要源自于Protocol Buffer的官方文档,而代码示例则抽取于一个公司内部项目的Demo。这样做不仅可以保持Google文档的良好风格和系统性,同时再结合一些比较实用和通用的用例,这样就更加便于公司内部的培训,以及和广大网友的技术交流。需要说明的是,Blog的内容并非line by line的翻译,其中包含一些经验性总结,与此同时,对于一些不是非常常用的功能并未予以说明,有兴趣的开发者可以直接查阅Google的官方文档。
一、为什么使用Protocol Buffer? 在回答这个问题之前,我们还是先给出一个在实际开发中经常会遇到的系统场景。比如:我们的客户端程序是使用Java开发的,可能运行自不同的平台,如:Linux、Windows或者是Android,而我们的服务器程序通常是基于Linux平台并使用C++开发完成的。在这两种程序之间进行数据通讯时存在多种方式用于设计消息格式,如: 1. 直接传递C/C++语言中一字节对齐的结构体数据,只要结构体的声明为定长格式,那么该方式对于C/C++程序而言就非常方便了,仅需将接收到的数据按照结构体类型强行转换即可。事实上对于变长结构体也不会非常麻烦。在发送数据时,也只需定义一个结构体变量并设置各个成员变量的值之后,再以char*的方式将该二进制数据发送到远端。反之,该方式对于Java开发者而言就会非常繁琐,首先需要将接收到的数据存于ByteBuffer之中,再根据约定的字节序逐个读取每个字段,并将读取后的值再赋值给另外一个值对象中的域变量,以便于程序中其他代码逻辑的编写。对于该类型程序而言,联调的基准是必须客户端和服务器双方均完成了消息报文构建程序的编写后才能展开,而该设计方式将会直接导致Java程序开发的进度过慢。即便是Debug阶段,也会经常遇到Java程序中出现各种域字段拼接的小错误。 2. 使用SOAP协议(WebService)作为消息报文的格式载体,由该方式生成的报文是基于文本格式的,同时还存在大量的XML描述信息,因此将会大大增加网络IO的负担。又由于XML解析的复杂性,这也会大幅降低报文解析的性能。总之,使用该设计方式将会使系统的整体运行性能明显下降。 对于以上两种方式所产生的问题,Protocol Buffer均可以很好的解决,不仅如此,Protocol Buffer还有一个非常重要的优点就是可以保证同一消息报文新旧版本之间的兼容性。至于具体的方式我们将会在后续的博客中给出。
二、定义第一个Protocol Buffer消息。 创建扩展名为.proto的文件,如:MyMessage.proto,并将以下内容存入该文件中。 message LogonReqMessage { required int64 acctID = 1; required string passwd = 2 } 这里将给出以上消息定义的关键性说明。 1. message是消息定义的关键字,等同于C++中的struct/class,或是Java中的class。 2. LogonReqMessage为消息的名字,等同于结构体名或类名。 3. required前缀表示该字段为必要字段,既在序列化和反序列化之前该字段必须已经被赋值。与此同时,在Protocol Buffer中还存在另外两个类似的关键字,optional和repeated,带有这两种限定符的消息字段则没有required字段这样的限制。相比于optional,repeated主要用于表示数组字段。具体的使用方式在后面的用例中均会一一列出。 4. int64和string分别表示长整型和字符串型的消息字段,在Protocol Buffer中存在一张类型对照表,即Protocol Buffer中的数据类型与其他编程语言(C++/Java)中所用类型的对照。该对照表中还将给出在不同的数据场景下,哪种类型更为高效。该对照表将在后面给出。 5. acctID和passwd分别表示消息字段名,等同于Java中的域变量名,或是C++中的成员变量名。 6. 标签数字1和2则表示不同的字段在序列化后的二进制数据中的布局位置。在该例中,passwd字段编码后的数据一定位于acctID之后。需要注意的是该值在同一message中不能重复。另外,对于Protocol Buffer而言,标签值为1到15的字段在编码时可以得到优化,即标签值和类型信息仅占有一个byte,标签范围是16到2047的将占有两个bytes,而Protocol Buffer可以支持的字段数量则为2的29次方减一。有鉴于此,我们在设计消息结构时,可以尽可能考虑让repeated类型的字段标签位于1到15之间,这样便可以有效的节省编码后的字节数量。
三、定义第二个(含有枚举字段)Protocol Buffer消息。 //在定义Protocol Buffer的消息时,可以使用和C++/Java代码同样的方式添加注释。 enum UserStatus { OFFLINE = 0; //表示处于离线状态的用户 ONLINE = 1; //表示处于在线状态的用户 } message UserInfo { required int64 acctID = 1; required string name = 2; required UserStatus status = 3; } 这里将给出以上消息定义的关键性说明(仅包括上一小节中没有描述的)。 1. enum是枚举类型定义的关键字,等同于C++/Java中的enum。 2. UserStatus为枚举的名字。 3. 和C++/Java中的枚举不同的是,枚举值之间的分隔符是分号,而不是逗号。 4. OFFLINE/ONLINE为枚举值。 5. 0和1表示枚举值所对应的实际整型值,和C/C++一样,可以为枚举值指定任意整型值,而无需总是从0开始定义。如: enum OperationCode { LOGON_REQ_CODE = 101; LOGOUT_REQ_CODE = 102; RETRIEVE_BUDDIES_REQ_CODE = 103;
LOGON_RESP_CODE = 1001; LOGOUT_RESP_CODE = 1002; RETRIEVE_BUDDIES_RESP_CODE = 1003; }
四、定义第三个(含有嵌套消息字段)Protocol Buffer消息。 我们可以在同一个.proto文件中定义多个message,这样便可以很容易的实现嵌套消息的定义。如: enum UserStatus { OFFLINE = 0; ONLINE = 1; } message UserInfo { required int64 acctID = 1; required string name = 2; } message LogonRespMessage { required LoginResult logonResult = 1; required UserInfo userInfo = 2; } 这里将给出以上消息定义的关键性说明(仅包括上两小节中没有描述的)。 1. LogonRespMessage消息的定义中包含另外一个消息类型作为其字段,如UserInfo userInfo。 2. 上例中的UserInfo和LogonRespMessage被定义在同一个.proto文件中,那么我们是否可以包含在其他.proto文件中定义的message呢?Protocol Buffer提供了另外一个关键字import,这样我们便可以将很多通用的message定义在同一个.proto文件中,而其他消息定义文件可以通过import的方式将该文件中定义的消息包含进来,如: import "myproject/CommonMessages.proto"
五、限定符(required/optional/repeated)的基本规则。 1. 在每个消息中必须至少留有一个required类型的字段。 2. 每个消息中可以包含0个或多个optional类型的字段。 3. repeated表示的字段可以包含0个或多个数据。需要说明的是,这一点有别于C++/Java中的数组,因为后两者中的数组必须包含至少一个元素。 4. 如果打算在原有消息协议中添加新的字段,同时还要保证老版本的程序能够正常读取或写入,那么对于新添加的字段必须是optional或repeated。道理非常简单,老版本程序无法读取或写入新增的required限定符的字段。
六、类型对照表。 .proto Type Notes C++ Type Java Type
double double double float float float
int32 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. int32 int
int64 Uses variable-length encoding. Inefficient for encoding negative numbers – 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. int64 long