Protocol Buffers编程指南与应用

Protocol Buffers
Protocol buffers,简称Protobuf,是一个独立于编程语言,独立于平台,且可拓展的自动序列化结构数据的机制。
本文档服务于想要在程序中使用Protobuf的JAVA,C++,Python开发者。概述中简单介绍了Protobuf,接下来将引导读者一步步开发自己的Protobuf程序。——包括更深一步的protocol buffer encoding。API reference documentation提供三种编程语言语法支持以及在书写.proto文件时的编程风格推荐。

开发者指导


什么是protocol buffers?

Protocol buffers提供了一种灵活、高效、自动序列化结构数据的机制,类比于 XML,但是它比 XML 更小、更快、更简单。仅需要自定义一次你所需的数据格式,然后用户就可以使用 Protobuf 编译器自动生成各种语言的源码,方便的读写用户自定义的格式化的数据。与语言无关,与平台无关,还可以在不破坏原数据格式的基础上,依据原有数据格式,更新现有的数据格式。


Protobuf如何工作

用户在 .proto 文件中定义 message 来指定所需要序列化的数据格式。每一个 message 都是一个小的信息逻辑单元,包含一系列的 name-value 值对。下面举例来说明一个简单的 .proto 文件,它定义了一条包含 Person 信息的 message。

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;
}

从以上代码来看,message 格式非常简单。每种类型的 message 包含一个或者多个唯一编码字段,每个字段由名称和值类型组成,值类型可以是数字(整形或者浮点型)、布尔值、字符串、原始字节,甚至是其他的 message(如上例所示)。Protobuf 允许 message 中包含 message,以达到分层嵌套。message 中可以定义 optional 字段、required 字段和 repeated 字段。

定义好 message 后,运行 Protobuf 编译器编译 .proto 文件,就可以生成存取数据的相关类。这些类包括简单的设置及读取字段(比如 name() 和 set_name() )的方法,也包括整个数据结构的 message 和原始字节之间的序列化/反序列化的转换方法。举个例子,如果你选择的是 C++ 语言,运行 Protobuf 编译器编译以上 .proto 文件生成 Person 类。你就能使用这个类去填充、序列化、检索 Person message。如下代码:

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

接下来,用如下代码来读取 message:

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

Protobuf 是易于扩展的,可以向后兼容,我们可以在 message 中添加新字段,在解析的时候,老版本的数据就会忽略新增加的字段。因此,如果现有通讯协议使用 Protobuf 做为其数据格式,可以直接扩展该通讯协议,而不必担心着将会破坏现有的代码。关于使用 .proto 文件生成目标代码,后面将会介绍。


为什么不直接使用XML

Protocol buffers在序列化结构数据上比XML具有更多的优势:

  • 更简单
  • 小3-10倍
  • 快20-100倍
  • 歧义更少
  • 生成的类更容易使用
    举个栗子,如果你想存储一个人的信息,包括姓名和邮箱地址,下面是XML的写法:
  <person>
    <name>John Doe</name>
    <email>jdoe@example.com</email>
  </person>

而对应的protocol buffer message(使用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"
}

当这个message被编码成protocol buffer二进制格式时(以上代码只是为了方便阅读和调试),只有大概28个字节长,100-200ns即可解析。而XML版本则最少需要69个字节,并且需要5,000-10,000ns解析时长。

同样的,操纵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 buffer也并非总是比XML好——比如说,protocol buffers并不适用于组建基于文本的文档标记,因为我们不能用简单的方法在文本中插入结构。此外,XML是易读性,和可编辑性更好的语言;protocol buffers的原始格式则不尽然。XML在某种程度上,是自解释的,而protocol buffers必须有消息定义(.proto文件)才能看出来是什么意思。


听起来很不错,哪怎么开始呢?

Download the package-包含了适用于Java,Python,和C++语言的源代码及编译器,以及I/O类和测试范例。根据README文件的指示,可以方便的安装编译器。
一旦上面的都做完了,请尝试跟着你所选择语言的入门指导完整的做一遍,将有助于你通过简单的例子来了解如何使用protocol buffers。


proto3介绍

最新版本是版本3,它有全新的语言版本:Protocol Buffers 3,和一些已经存在于proto2中的新特性。Proto3简化了protocol buffer语言,不仅易用性大大提升,而且支持更多编程语言:Java,C++,Python,Java Lite,Ruby,JavaScript,Objective-C,和C#。此外通过最新的Go protoc插件,还能生成用于Go语言的proto3代码,戳此github仓库golang/protobuf。更多的语言支持正在开发中。

目前我们只建议你在以下情况之一选择proto3:

  • 你的项目所使用的语言是proto3刚刚支持的。
  • 希望尝试使用我们最新的开源软件gRPC-强烈建议使用proto3来避免兼容性问题。

请注意,proto3和proto2的API并不是完全兼容的。为了避免兼容性问题,我们将在新的protocol buffers发行版本中支持先前的语言。

在当前的发行版本文档中可以了解proto3语法的主要变化,proto3的开发者文档即将出版!

(如果proto2和proto3的名字让你感到不解,这是因为我们当初开源protobuf时,它已经是谷歌的第二个版本,也被称为proto2。这也是为什么我们的开原版本号从v2.0.0开始的原因。)


历史漫谈

Protobuf最初是谷歌开发用来解决索引服务器的请求/响应协议的。在使用Protobuf之前,有一种格式用以处理请求&响应数据的编码和解码工作,并且支持多种版本的协议。这使得写出来的代码非常丑陋,比如:

if (version==3) {
    ...
}else if (version>4) {
    if (version==5) {
        ...
    }
    ...
}

通信协议因此变得越来越复杂,因为开发者必须确保请求者和接受者互相兼容,并且在一方开始使用新协议时,另外一方也要使用新的协议。

Protobuf可用于解决下类问题:

  • 自动生成序列化与反序列化代码,避免人工处理编码问题。
  • 除了用于短期RPC(远程过程调用)请求之外,开发者还使用该协议作为一种便捷的自描述格式,用于数据持久化。
  • RPC服务器接口可以作为 .proto 文件来描述,而通过ProtocolBuffer的编译器生成存根(stub)类供用户实现服务器接口。

Protobuf现在已经是Google的混合语言数据标准了,现在已经正在使用的有超过48,162种报文格式定义和超过12,183个 .proto 文件。他们用于RPC系统和持续数据存储系统。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值