67.protobuf入门

转载请注明原始链接:http://blog.csdn.net/a464057216/article/details/54896886

后续此博客不再更新,欢迎大家搜索关注微信公众号“测开之美”,测试开发工程师技术修炼小站,持续学习持续进步。
在这里插入图片描述

简介

Protocol Buffers(也叫Protobuf,简称PB)是Google的一种可扩展的用于将结构化数据序列化的技术,独立于平台、独立于语言,可以用于数据通信、存储等领域。同XML相比,PB更轻量、更快、更简单。定义好如何存储结构化数据以后,可以方便地通过编译产物从/向不同的数据流读/写数据,并且不受限于开发语言。目前PB支持C++、Java、Python,新版本的proto3还支持Java Lite、Ruby、Javascript、Objective-C、C#、go等,更多语言支持在逐渐加入进来。

官方仓库位于GitHub。使用PB需要安装PB编译器protoc和不同语言的PB运行时支持。protoc的下载可以也访问GitHub,或者从maven获取历史版本。

定义message类型

.proto文件中定义数据如何组织,一个message是一个逻辑上独立的信息记录,包含多个name-value对(name-value pair,也叫域field),官方建议message的名字使用CamelCase。比如:

message Person {
  required string name = 1; //=1、=2是每个域在二进制编码中唯一的标识号
  required int32 id = 2;
  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;
}

每个域包含域规则、类型、名字和标识号等字段。

域规则

域规则包括required、optional、repeated:

  • required:格式良好的message应该有且只有一个required域。required域必须设置该域的值,否则message被认为是未初始化的,未初始化的message在序列化或解析时会抛异常。

  • optional:格式良好的message可以没有或只有一个optional域。optional域的值可以设置也可以不设置,如果未设置optional域的值,则采用默认值,默认值的设置放在标识号的后面,如果没有设置默认值,则采用系统默认规则:整型默认值是0,string类型默认值是空字符串,bool类型默认值是false,枚举类型的默认值是定义枚举时的第一个值,对于message类型,默认值是其所有域都没有被set的一个默认实例。

  • repeated:格式良好的message中repeated域可以重复存在任意次(包括零次),重复的值的顺序也会保留。由于历史原因,标量数值类型的repeated域没有被高效编码,新代码中用户应该使用[packed=true]保证更高效的编码,比如:

repeated int32 samples = 4 [packed=true];

域类型

类型可以是标量类型或者复合类型如message、enum等。

标量类型

.proto类型C++类型备注
doubledouble
floatfloat
int32int32使用可变长编码方式。编码负数不够高效,如果字段可能含有负数,使用sint32。
int64int64使用可变长编码方式。编码负数不够高效,如果字段可能含有负数,使用sint64。
uint32uint32使用可变长编码方式。
uint64uint64使用可变长编码方式。
sint32int32使用可变长编码方式。有符号的整型值。
sint64int64使用可变长编码方式。有符号的整型值。
fixed32uint32总是4个字节。如果数值总是比总是比228大的话,这个类型会比uint32高效。
fixed64uint64总是8个字节。如果数值总是比总是比256大的话,这个类型会比uint64高效。
sfixed32int32总是4个字节。
sfixed64int64总是8个字节。
boolbool
stringstring一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。
bytesstring可能包含任意顺序的字节数据。

复合类型

枚举类型

官方建议枚举的名字使用CamelCase,枚举中每个值的名字使用CAPITALS_WITH_UNDERSCORES形式,比如:

enum Foo{
    FIRST_VALUE = 1;
    SECOND_VALUE = 2;
}

值与值之间用分号分隔。一般情况下,不允许为不同的字面量定义相同的值,在枚举定义中开启了allow_alias开关时才允许有别名,比如:

enum EnumAllowAlias {
    option allow_alias = true;
    UNKOWN = 0;
    STARTED = 1;
    BEGIN = 1;
}

枚举值的取值范围不能超过32bit,由于内部使用变长编码,考虑到效率不推荐枚举存储负数。枚举可以定义在message中,或message外(此时该枚举可以被同一个.proto文件中的其他message使用)。如果枚举定义在message中,同一个.proto文件中其他message想要使用该枚举类型时,可以使用MessageType.EnumType的语法。

message类型

使用message类型用来定义嵌套的message结构,比如:

message SearchResponse {
  repeated Result result = 1;
}

message Result {
  required string url = 1;
}

message也可以嵌套定义,并且可以嵌套任意层:

message SearchResponse {
  repeated Result result = 1;
  message Result {
      required string url = 1;
  }
}

域名字

官方建议域的名字使用小写字母且下划线分隔的形式。

标识号

推荐为频繁使用的域使用 [1,15]之内的标识号(注意为将来可能常用的域预留标识号)。不可使用[19000-19999]的标识号(Protobuf预留)。可用标识号最大到2^29 - 1即536870911。一个标识号一旦被占用,在未来升级message的时候,这个标识号永远都不能再被使用了,可以使用reserved声明表示标识号不能再被使用(比如某些域被删除的情形):

message Foo {
    reserved 2, 15, 9 to 11; //标识号可以使用a to b的形式,左闭右闭
    reserved "foo", "bar"; //字符串表示域名
    reserved 14, "xx"; //可以混合域名和标识号
}

导入定义

如果想引用其他.proto文件中定义的message,可以在.proto文件开头使用import语句(以分号结尾)。import不会做递归处理即只能使用直接import的.proto文件中的定义。

如果被import的.proto文件移动到了新的位置,可以在旧位置编辑一个哑.proto文件,该哑.proto文件通过import public将外层import请求转到新的位置,比如:

//new.proto ——定义被移动到了这
//old.proto ——哑.proto文件
import public "new.proto"
import "other.proto"
//client.proto
import "old.proto"

按照上面的组织结构,client.proto中可以使用old.proto和new.proto中的定义,但是不能使用other.proto中的定义。

最后,一个.proto文件中可以定义多个相关联的message。.proto文件采用C++风格的单行注释(//)。

使用PB编译器编译

protoc编译器可以根据.proto文件生成不同语言的代码,这些代码包含获取和设置message各个域的方法、将message序列化到输出流的方法、从输出流解析出message的方法等。

  • C++:每个.proto文件生成一个.h.cc文件,每个message对应一个类的定义。
  • Python:根据.proto文件生成一个模块(.py文件),该模块包含每个message对应的静态描述符,在运行时通过metaclass生成必要的Python数据访问类。

比如生成C++的数据访问类使用如下命令:

protoc --cpp_out=. Person.proto

生成Python的数据访问类使用如下命令:

protoc --python_out=. Person.proto

也可以使用-IPATH, --proto_path=PATH参数设置import语句的搜索路径,如果指定了多个路径,则按照给定路径顺序寻找,如果没有设置-I参数,默认从protoc命令执行目录搜索。

如果觉得我的文章对您有帮助,欢迎关注我(CSDN:Mars Loo的博客)或者为这篇文章点赞,谢谢!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值