使用Google Protocol Bufffers进行通信(Ruby & C)

最近项目中需要用到Google 的 proto buffer作为一种跨平台通信的协议。首先感谢 的博客,让我对这个协议有了一些初步的理解。

协议的由来
在后台需要与多种终端如iPhone,Android,Web或者WinPhone之类的不同平台作通信的时候,常常需要使用一种中间的通信协议,并且使用通用数据类型如XML。现在项目中的设备底层是用c语言完成的,我们服务端的语言是ruby,中间层是IOS或者Andriod的设备。

Protocol Buffers(以下简称protobuf)就是类似于XML这样的东西,可以在后台与多终端间进行通信,但是比它要远强大的多。

Protobuf由Google出品,08年的时候Google把这个项目开源了,截至发稿已发展到2.5.0版本,官方支持C++,Java和Python三种语言,但是由于其设计得很简单,所以衍生出很多第三方的支持,基本上常用的PHP,C,ruby等多种语言都已有第三方的库。

Protobuf的优势
首先我们来比较和XML来比较一下,其实最主要的优势就是它更简单了。

一个XML文件我们编写的时候需要定义各种各种的节点,而Proto文件则使用Google定义的有点像Java的语言来编写,简洁很多。

XML长得像这样,看起来很冗余,因为要加很多标签:

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

而我们的proto文件则长这样:

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

其次是快了。proto文件是给程序猿阅读的时候用的,真正传输的时候是序列化的二进制数据,比起XML要小得多,解析起来也快得多。

第三是可以直接生成供程序使用的类。XML文件接收后我们还得手工去解析然后转化为可以使用的对象,但是PB文件接收后,PB的库就已经帮我们转化为对应的数据类了。

Protobuf主要分为两个部分,一是编译器protoc,一是分包组包所用到的库。
编译器是用来编译proto文件为目标语言的,比如一个上面那个 Person.proto 文件,我可以用 protoc 直接编译成C++类 Person,用的时候就很方便了:

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

使用
我们现在的后台开发中,主要用到的是Ruby on Rails, 所以我们先来着重看一看protobuf在Rails中的使用方法。

  1. 定义好proto的文件
package Tutorial;

message Source {
    required string title = 1;
    required string description = 2;
    optional int id = 3;
}

message SourceAllResponse {
    required uint32 count = 1;
    repeated Source source_list = 2;
}
  1. 编译成对应语言

定义完proto文件后,使用官方的 protoc 可以对其进行编译。下载地址在: https://code.google.com/p/protobuf/downloads/list

如果是 Mac OS X 或者 Linux ,需要下载官方的源码,解压后根据官方的 README.txt 里的说明:

$ ./configure
$ make
$ make check
$ make install
  1. Ruby的用法:
    待补充

Protobuf 语法定义
首先我们再来定义一个proto文件,结构如下:

message Article {
required int32 article_id=1;
optional string article_excerpt=2;
repeated string article_picture=3;
}

上面我们主要定义了一个消息,这个消息包括文章ID,文章摘要,文章图片。下面给出消息定义的相关说明:

名称定义
message是消息定义的关键字
required表示这个字段必须的,必须在序列化的时候被赋值
optional代表这个字段是可选的,可以为0个或1个但不能大于1个
repeated则代表此字段可以被重复任意多次包括0次
int32和string字段的类型,后面是我们定义的字段名

最后的1,2,3则是代表每个字段的一个唯一的编号标签,在同一个消息里不可以重复。这些编号标签用与在消息二进制格式中标识你的字段,并且消息一旦定义就不能更改。需要说明的是标签在1到15范围的采用一个字节进行编码。所以通常将标签1到15用于频繁发生的消息字段。编号标签大小的范围是1到229,此外不能使用protobuf系统预留的编号标签(19000 -19999)。当然protobuf支持更多的类型,比如bool, double, float, emun, 也可以是其他定义过的消息类型譬如前面的消息Article。

下面让我们定义一个数据比较多的article.proto文件来再次说明下proto语法的相关内容,起码通过列子可以更直观的感受:

syntax = "proto3";
package zji.proto;
message Article {
  required int32 article_id = 1;
  optional string article_excerpt = 2;
  repeated string article_picture = 3;
  optional int32  article_pagecount = 4 [default = 0];
  enum ArticleType {
    NOVEL = 0;
    PROSE = 1;
    PAPER = 2;
    POETRY = 3;
  }
  optional ArticleType article_type = 5 [default = NOVEL];
  message Author {
    required string name = 1; //作者的名字
    optional string phone = 2;
  }
  optional Author author = 6;
  repeated int32 article_numberofwords = 7 [packed=true];
  reserved  9, 10, 12 to 15;
  extensions 100 to 1000;
}
extend Article {
  optional int32 followers_count = 101;
  optional int32 likes_count= 102;
}
message Other {
  optional string other_info = 1;
  oneof test_oneof {
    string code1 = 2;
    string code2 = 3;
  }
}

reserved关键字: 主要用于保留相关编号标签。这么做的目的就是防止更新proto文件删除了某些字段,而未来的使用者定义新的字段时重新使用了该编号标签。这会引起一些问题,比如在获取老版本的消息时,会引起譬如数据冲突等一些隐藏的bug,所以一定要用reserved标记这些编号标签以保证不会被使用。其实对这个关键字的用法理解得并不是很深刻,后面有机会用到我们再补充。

extent关键字:当我们需要对消息进行扩展的时候,我们可以用extensions关键字来定义一些编号标签供第三方扩展。这样的好处是不需要修改原来的消息格式。就像上面proto文件,我们用extend关键字来扩展。只要扩展的字段编号标签在extensions定义的范围里。

oneof关键字: 待补充

packed=true的作用: 对于基本数值类型,由于历史原因,不能被protobuf更有效的encode。所以在新的代码中使用packed=true可以更加有效率地encode。注意packed只能用于repeated 数值类型的字段。不能用于string类型的字段。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值