iOS -- Protocol Buffers概览

Protocol Buffers概览

开发向导

欢迎来到protocol buffers的开发者文档,protocol buffers是语言中立,平台中立,易于扩展的结构化数据序列化方法,它可以用在通讯协议,数据存储等方面。

这份文档的目标读者是试图在应用中使用protocol buffers的Java, C++或者Pytho开发者。这份概览告诉你如何开始-然后你可以去教程或者深入到protocol buffer编码API参考文档同样以三种语言提供,包括编写.proto文件的编程语言代码风格指导。

什么是protocol buffers?

Protocol buffers是一种可伸缩,高效的,自动化的结构化数据序列化机制,它比较像XML但是更小,更快,更简单。定义好你的数据结构,然后你就可以使用生成的特殊的源代码读写你的结构化数据,数据来源可以是各种数据流,也可以使用各种编程语言。你甚至可以在不破坏使用旧格式编译并已经部署的程序的情况下更新数据结构。

--------------------------------

  有了这种代码生成机制,开发人员再也不用吭哧吭哧地编写那些协议解析的代码了(干这种活是典型的吃力不讨好)。
  万一将来需求发生变更,要求给订单再增加一个“状态”的属性,那只需要在Order.proto文件中增加一行代码。对于发送方(模块A),只要增加一行设置状态的代码;对于接收方(模块B)只要增加一行读取状态的代码。哇塞,简直太轻松了!
  另外,如果通讯双方使用不同的编程语言来实现,使用这种机制可以有效确保两边的模块对于协议的处理是一致的。
  顺便跑题一下。
  从某种意义上讲,可以把proto文件看成是描述通讯协议的规格说明书(或者叫接口规范)。这种伎俩其实老早就有了,搞过微软的COM编程或者接触过CORBA的同学,应该都能从中看到IDL(详细解释看“这里 ”)的影子。它们的思想是相通滴。

  ◇支持“向后兼容”和“向前兼容”
  还是拿刚才的例子来说事儿。为了叙述方便,俺把增加了“状态”属性的订单协议成为“新版本”;之前的叫“老版本”。
  所谓的“向后兼容”(backward compatible),就是说,当模块B升级了之后,它能够正确识别模块A发出的老版本的协议。由于老版本没有“状态”这个属性,在扩充协议时,可以考虑把“状态”属性设置成非必填 的,或者给“状态”属性设置一个缺省值(如何设置缺省值,参见“这里 ”)。
  所谓的“向前兼容”(forward compatible),就是说,当模块A升级了之后,模块B能够正常识别模块A发出的新版本的协议。这时候,新增加的“状态”属性会被忽略。
  “向后兼容”和“向前兼容”有啥用捏?俺举个例子:当你维护一个很庞大的分布式系统时,由于你无法同时 升级所有 模块,为了保证在升级过程中,整个系统能够尽可能不受影响,就需要尽量保证通讯协议的“向后兼容”或“向前兼容”。


他们如何工作的?

通过在.proto文件中定义protocol buffer消息类型,说明需要被序列化的信息需要保持什么样的结构。一个protocol buffer消息是一小片信息的逻辑记录,包含一系列的名称-值对。这里是一个非常基础的例子,他定义了包含个人信息的消息:

message Person {
  required string name = 1;
  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;
}

可以看到,消息格式很简单 - 每个消息有一个或多个编号的字段,每个字段有一个名字和一个类型,类型可以是数字(整形或浮点),布尔,字符串,原生字节或是其他protocol buffer消息类型(如上例)。你可以指明可选字段,必选字段和重复字段。关于编写.proto文件的更多信息请见Protocol Buffer语言指导

定义好消息后,就可以运行针对你的程序语言的protocol buffer编译器来编译.proto文件。这些类对每个字段提供简单存取器(例如query()和set_query())和序列化整个结构到原生字节或从原生字节解析结构的方法的。然后你可以在程序中用这个Persion类生成,序列化或者从protocl buffer消息中取得Person对象。你可能写这样的代码来操作:

Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("jdoe@example.com");
fstream output("myfile", ios::out| ios::binary);
person.SerializeToOstream(&output);

然后你可以马上读回消息:

fstream input("myfile", ios::in| ios::binary);
Person person;
person.ParseFromIstream(&input);
cout <<"Name: "<< person.name()<< endl;
cout <<"E-mail: "<< person.email()<< endl;

你可以在消息中添加新的字段而不破坏向后的兼容性。老的程序在解析时简单的忽略新字段。所以如果你使用protocol buffers作为你的通讯协议的数据格式,你可以扩展你的协议而不用担心破坏既有的代码。

你可以在API参考找到使用生成的protocol buffer代码的完整的参考,在Protocol Buffer编码有更多关于protocol buffer消息如何编码的信息。

Why not just use XML?干嘛不直接用XML?

相较于XML,Protocol buffers在序列化结构化数据方面有许多优点。它:

  • 更简单
  • 3至10倍小
  • 快20-100倍
  • 更少的模糊性
  • 对编程来讲,生成数据访问类更容易使用。
  • 比较
    XML | JSON | PB | Lua 
    数据结构支持 | 复杂结构 | 简单结构 | 较复杂结构 | 复杂结构 
    数据保存方式 | 文本 | 文本 | 二进制 | 文本 
    数据保存大小 | 大 | 一般 | 小 | 一般 
    解析效率 | 慢 | 一般 | 快 | 稍快 
    语言支持程度 | 非常多 | 多 | C++/Java/Python | 多 
    开发难度?繁琐? | 繁琐 | 简单 | 简单 | 相对繁琐 
    学习成本 | 低 | 低 | 低 | 高 
    适用范围 | 数据交换 | 数据交换 | 数据交换 | 数据保存及脚本处理

比如说,你想建模一个person,它有name和email。如果用XML,你需要写:

  <person>
    <name>John Doe</name>
    <email>jdoe@example.com</email>
  </person>

然而对应的protocol buffer消息( protocol buffer 文本格式)是这样:

# Textual representation of a protocol buffer.
# This is *not* the binary format used on the wire.
person {
  name: "John Doe"
  email: "jdoe@example.com"
}

当这个消息被编码为二进制格式(文本格式)后,可能只有28字节长,并且解析只需要大约100-200纳秒。XML的版本至少69字节不包括空格,需要花费5,000-10,000纳秒解析。

Also, manipulating a protocol buffer is much easier:同样,操作protocol buffer也容易得多:

  cout <<"Name: "<< person.name()<< endl;
  cout <<"E-mail: "<< person.email()<< endl;

而用XML你得这样写:

  cout <<"Name: "
       << person.getElementsByTagName("name")->item(0)->innerText()
       << endl;
  cout <<"E-mail: "
       << person.getElementsByTagName("email")->item(0)->innerText()
       << endl;

然而,protocol buffers并不总是比XML好 - 例如,protocol buffers就不适合建模基于文本的有标记文档(如HTML),因为你很难在文字中插入结构信息。另外,XML是可读的并且易于手工编辑的;protocol buffers,至少在原生格式上不是这样。XML还是(某种程度上)自描述的。而protocol buffer仅仅在你有关于它的定义文件(.proto文件)的时候才有意义。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值