您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 经营企划 > 新媒技术大讲堂-protobuf序列化协议及应用
ProtocolBuffers序列化协议及应用基础业务开发部高磊2010年10月15日自我介绍•基础业务开发部高级技术经理•2006年开始参与飞信个人版服务器端的开发•负责个人版服务器端的系统架构规划•正在进行下一代服务器端平台FAE的设计与开发ProtocolBuffers•ProtocolBuffers是Google开发的一种数据描述语言,能够将结构化数据序列化,可用于数据存储、通信协议等方面•官方网站•License-NewBSDLicense–如果再发布的产品中包含源代码,则在源代码中必须带有原来代码中的BSD协议。–如果再发布的只是二进制类库/软件,则需要在类库/软件的文档和版权声明中包含原来代码中的BSD协议。–不可以用开源代码的作者/机构名字和原来产品的名字做市场推广Agenda•快速开始•语言及协议规范•开发示例•性能对比•RPC及应用准备工作•访问官方网站•下载SDK=protobuf-2.3.0.zip•如果不想自己编译,下载protoc工具=protoc-2.3.0-win32.zip编写.proto描述文件messagePerson{requiredstringname=1;requiredint32id=2;optionalstringemail=3;enumPhoneType{MOBILE=0;HOME=1;WORK=2;}messagePhoneNumber{requiredstringnumber=1;optionalPhoneTypetype=2[default=HOME];}repeatedPhoneNumberphone=4;}用protoc生成访问代码•保存为person.proto文件•运行–protoc--cpp_out=srcperson.proto•得到如下文件–person.pb.cc–person.pb.h•其他语言–Java:protoc–java_out=srcperson.proto–Python:protoc–python_out=srcperson.proto–C#:使用第三方工具protobuf.net编写应用代码Personperson;person.set_name(JohnDoe);person.set_id(1234);person.set_email(jdoe@example.com);fstreamoutput(myfile,ios::out|ios::binary);person.SerializeToOstream(&output);fstreaminput(myfile,ios::in|ios::binary);Personperson;person.ParseFromIstream(&input);coutName:person.name()endl;coutE-mail:person.email()endl;为什么不用XML•在序列化结构化的数据时,相比与xml,protobuf有如下优点–简洁–消息大小只需要xml的1/10~1/3–解析速度快20~100倍–减少了二义性–可以生成更容易在编程中使用的数据访问代码消息体对比•XML(82bytes)personid1234/idnameJohnDoe/nameemailjdoe@example.com/email/person•ProtocolBuffers(31bytes)0A//Name字段标识13|2(字段类型:2,length-delimited)084A6F686E20446F65//08是字符串长度,后面是JohnDoe10//Id字段标识23|0(字段类型:0,数字)D209//1234通过变长编码得到1A//email字段标识33|2(字段类型:2,length-delimited)106A646F65406578616d706C652E636F6D//10是字符串长度,后面jdoe@example.comprotobuf解决的问题•跨平台,跨语言•向下兼容性好,格式升级毫无压力•一次定义,多次生成,完全避免手写枯燥乏味且容易出错的解析代码•特别方便用于Rpc和消息存储的场合Protocolbuffers现在是Google内部的标准数据定义语言,在Google代码树种,现在有48,162种不同的消息定义在12,183个.proto文件中,用在RPC和数据存储的场合。(引用自)Agenda•快速开始•语言及协议规范•开发示例•性能对比•RPC及应用定义消息类型•确定消息命名•定义字段类型•分配字段序号–序号范围1~229-1,除去19000~19999区间–序号是序列化的依据,名字只是参考messageSearchRequest{requiredstringquery=1;optionalint32page_number=2;[default=10];optionalint32result_per_page=3;[default=10];}字段约束•required:必须赋值字段,禁止为空•optional:可选字段,可以为空,–[default=]默认值,如果一端报文中不包含可选字段,那么可选字段在反序列化的时候会赋为默认值,如果没有确定默认值,则可选字段将会使用类型的默认值,boolean为false,数字类型为0•repeated:集合,可以填充零到多个对象,messageSearchRequest{requiredstringquery=1;optionalint32page_number=2;[default=10];optionalint32result_per_page=3;[default=10];}定义更多的类型•在同一个.proto文件中可以定义多个message•可以用C++风格的//起始的注释messageSearchRequest{requiredstringquery=1;optionalint32page_number=2;//请求的页码optionalint32result_per_page=3;//每页返回的值}messageSearchResponse{...}运行protoc生成代码•当编写好.proto文件后,运行protoc编译器,会生成你选择语言的代码,针对不同的语言有不同的效果–C++:编译器会为每个.proto文件生成.h和.cc文件,为每个message生成一个class–Java:编译器会为每个message生成一个.java文件–Python:有一些小小的不同,python编译器会针对每个message生成一个静态的descriptor,–C#:C#目前为非官方支持,可以用protobuf.net生成C#实体类,也可以直接用Attribute描述写成标量类型protoTypeC++TypeJavaTypeC#Type(protobuf.net)Notesdoubledoubledoubledoublefloatfloatfloatfloatint32int32intint变长编码,对负数效率低,请用sint32int64int64longlong变长编码,对负数效率低,请用sint32uint32uint32intuint变长编码uint64uint64longulong变长编码sint32int32intint变长编码,对负数效率比int32高sint64int64longlong变长编码,对负数效率比int64高标量类型(续)protoTypeC++TypeJavaTypeC#Type(protobuf.net)Notesfixed32uint32intuint固定4个字节,针对大于228的数据效率高fixed64uint64longulong固定8个字节,针对大于256的数据效率高sfixed32int32intint固定4个字节sfixed64int64longlong固定8个字节boolboolbooleanboolstringstringStringstring字符串需要UTF8或ASC-7编码bytesstringByteStringbyte[]Base-128Varints整数变长编码•每个字节使用使用低7位表示数字,除了最后一个字节,其他字节的最高位都设置为1,例如:–数字1:00000001–数字300:101011000000001000000100101100→0000010++0101100→100101100→256+32+8+4=300消息格式•一个ProtocolBuffers的消息包含一系列字段,每个字段由一个变长32位整数作为字段头,后面跟随字段体•字段头格式(field_number3)|wire_type-field_number:字段序号-wire_type:字段编码类型字段编码类型TypeMeaningUsedFor0Varintint32,int64,uint32,uint64,sint32,sint64,bool,enum164-bitfixed64,sfixed64,double2Length-delimitedstring,bytes,embeddedmessages,packedrepeatedfields3Startgroupgroups(deprecated)4Endgroupgroups(deprecated)532-bitfixed32,sfixed32,float编码示例1:整数编码•a=150时,编码如下08960108:13|09601:1010110000000010→01011000000010→150messageTest1{requiredint32a=1;}编码示例2:字符串编码•b=testing时,编码如下120774657374696e6712:23|207:字符串长度74657374696e67→testingmessageTest2{requiredstringb=2;}编码示例3:嵌套编码•设置c.a=150时,编码如下1a030896011a:33|203:嵌套结构长度089601→Test1{a=1}messageTest3{requiredTest1c=3;}其他编码规范•optional的字段不会出现在消息报文中•repeated的字段会出现多次(没设置[packed=true])的情况下–[packed=true]选项可以针对整数字段进行优化messageTest4{repeatedint32d=4;}d={3,270,86942};22//tag(fieldnumber4,wiretype2)06//payloadsize(6bytes)03//firstelement(varint3)8E02//secondelement(varint270)9EA705//thirdelement(varint86942)定义枚举类型•枚举类型使用变长编码,必须为32位整数messageSearchRequest{requiredstringquery=1;optionalint32page_number=2;optionalint32result_per_page=3[default=10
本文标题:新媒技术大讲堂-protobuf序列化协议及应用
链接地址:https://www.777doc.com/doc-4765778 .html