Protobuf全称Google Protocol Buffers,Protobuf是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

一、什么是序列化?
序列化和反序列化几乎是工程师们每天都要面对的事情,但是要精确掌握这两个概念并不容易。不同的计算机语言中,数据结构,对象以及二进制串的表示方式并不相同,序列化为的是解决跨语言、跨平台的通讯问题。序列化后的数据当然不能是某种语言的特殊数据类型,常用的序列化协议有XML、JSON、Protobuf等。

  • 序列化: 将数据结构或对象转换成二进制串的过程。
  • 反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。

二、相比其他序列化协议
不了解Protocol Buffers的同学可以把它理解为更快、更简单、更小的JSON或者XML,区别在于Protocol Buffers是二进制格式,而JSON和XML是文本格式。
相对于XML、JSON,Protocol Buffers的具有如下几个优点:

  • 简洁
  • 体积小:消息大小只需要XML的1/10 ~ 1/3
  • 速度快:解析速度比XML快20 ~ 100倍
  • 使用Protocol Buffers的编译器,可以生成更容易在编程中使用的数据访问代码
  • 更好的兼容性,Protocol Buffers设计的一个原则就是要能够很好的支持向下或向上兼容。

三、如何使用?
1、安装protoc编译器

cd ...
make 
make install

https://github.com/google/protobuf

2、定义.proto文件

syntax = "proto2";
message Request
{
    required int32 userid = 1;  // 用户id
    optional int32 type = 2;    // 用户类别
    repeated string desc = 3 [packed=true];  // 用户描述
}

上面定义的proto文件包含一个message,名字叫Request,并且在这个结构体里我们定义了三个字段,syntax指定proto版本,目前最新版本为proto3。proto文件定义好了,也就是说,传输与序列化、反序列化的协议已经定义好了,我们进行下一步,需要把这个proto文件生成目标语言代码。

3、proto语法
(1)上面定义了三个标量,两个整型&一个字符串类型,当然也可以定义枚举或者导入已有proto文件中的类型。
(2)在消息定义中,每个字段都有唯一的一个数字标识符。[1,15]之内的标识号在编码的时候会占用一个字节。[16,2047]之内的标识号则占用2个字节。所以应该为那些频繁出现的消息元素保留[1,15]之内的标识号
(3)指定字段规则

  • required:一个格式良好的消息一定要含有1个这种字段。表示该值是必须要设置的;
  • optional:消息格式中该字段可以有0个或1个值(不超过1个)。
  • repeated:在一个格式良好的消息中,这种字段可以重复任意多次(包括0次),可使用特殊选项[packed=true]来保证更高效。

4、编译proto文件到目标语言
当用protocolbuffer编译器来运行.proto文件时,编译器将生成所选择语言的代码,这些代码可以操作在.proto文件中定义的消息类型,包括获取、设置字段值,将消息序列化到一个输出流中,以及从一个输入流中解析消息。

  • 对C++来说,编译器会为每个.proto文件生成一个.h文件和一个.cc文件,.proto文件中的每一个消息有一个对应的类。
  • 对Java来说,编译器为每一个消息类型生成了一个.java文件,以及一个特殊的Builder类(该类是用来创建消息类接口的)。
  • 对Python来说,有点不太一样——Python编译器为.proto文件中的每个消息类型生成一个含有静态描述符的模块,,该模块与一个元类(metaclass)在运行时(runtime)被用来创建所需的Python数据访问类。

四、Python demo
1、安装protobuf Python库

pip install protobuf

2、生成Search_pb2.py文件

protoc --python_out=./ ./Search.proto 

3、序列化

# -*- coding: utf-8 -*-
import Search_pb2

# 序列化
search = Search_pb2.Search()
search.userid = 100
search.type = 2
search.desc.append('nantong')
search.desc.append('baidu')
trans = search.SerializeToString()
# 反序列化
recv = Search_pb2.Search()
recv.ParseFromString(trans)
print recv.userid
print recv.desc

SerializeToString函数序列化message和以字符串的方式返回。 注意,这是二进行字节,不是一个文本; 我们只使用str类型作为一个方便的容器。

五、PHP demo
1、安装protobuf PHP库
composer require "google/protobuf"

2、生成Search.pb.php文件
PHP只支持proto3协议,proto3语法去除了required,optional选项变成default的了

protoc --php_out=./ ./Search.proto

3、序列化

require 'Search.pb.php'
$from = new Search();
$from->setUserid(100);
$from->setType('2');
$from->getRepeatedInt32()[] = 'nantong';
$from->getRepeatedInt32()[] = 'baidu';
// 序列化
$data = $from->encode();
// 反序列化
$to->decode($data);
echo $to->getUserid();
echo $to->getDesc();


1、Mac下编译protobuf扩展
(1)EI Capitan授权
重启command R进入终端,csrutil disable
(2)安装pecl

cd /usr/lib/php 
sudo php install-pear-nozlib.phar 

(3)PHP升级
Mac自带PHP版本过低,protobuf需要PHP 5.5.9 or newer

brew update                # 更新brew软件
brew upgrade               # 更新软件包
brew install php56         # 安装php5.6

安装后的目录:/usr/local/Cellar/php56
(4)编译protobuf

sudo pecl install protobuf-3.1.0a1

2、参考:
Google Protocol Buffer 的使用和原理
Protocol Buffers序列化协议及应用
Protobuf 语法指南
Protobuf 的 proto3 与 proto2 的区别
mac通过homebrew升级php到5.6

标签: google, Protobuf, PB

评论已关闭