Protobuf:高效数据结构化工具
在上一篇文章, 基于PHP的socket实现了简单的RPC功能。但是在开发过程中,由于TCP的长连接和频繁数据包传输, 一般都会对数据进行压缩。
Protobuf是Google开源的一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。具备以下特点:
- 语言无关、平台无关,支持 Java、C++、Python、PHP等多种语言,支持多个平台;
- 数据量小,解析速度快,比XML数据格式快20~100倍,比JSON快5~10倍;
在RPC开发中,多用Protobuf来作为数据交换协议,例如著名的rpc框架:gRPC
protobuf的使用很简单,按照一定的语法定义结构化的消息格式,然后用自带的编译工具(protoc),将自动生成对应语言相关的类.
# Protoc安装
在使用protobuf之前,我们需要依据protobuf结构化语法定义结构化文件,再使用protoc将结构化文件生成各种语言的类。
Git:https://github.com/protocolbuffers/protobuf (opens new window)
Doc:https://developers.google.com/protocol-buffers/docs/proto3 (opens new window)
先安装protoc:
sudo apt-get install libtool
# 下载安装包
wget https://github.com/protocolbuffers/protobuf/archive/master.zip
unzip master.zip
cd protobuf-master
./autogen.sh
# 配置编译参数
./configure --prefix=/usr/local/protobuf
# 编译
make
# 安装
sudo make install
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
可以将protobuf安装路径protoc所在的目录,加入到环境变量中,便于我们快速调用protoc命令。
# Protobuf
export PATH=$PATH:/usr/local/protobuf/bin
1
2
2
# 定义消息类型
以官方文档为例,先定义一个Person
消息类型
syntax = "proto3";
message Person {
string name = 1;
int32 id = 2;
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
PhoneNumber phone = 4;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
进行protoc编译,生成对应的php类:
protoc --php_out=./ person.proto
1
编译后目录结构:
# 序列化/反序列化
我们需用composer引用google/protobuf库来调用protobuf:
编写composer.json:
{
"name": "php-protobuf",
"description": "PHP Protobuf Test",
"keywords": ["protobuf"],
"license": "MIT",
"type": "project",
"require":{
"google/protobuf":"3.9.0"
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
安装依赖包:composer install
编写代码,测试序列化/反序列化:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
require('./vendor/autoload.php');
require('./GPBMetadata/Person.php');
require('./Person/PhoneNumber.php');
require('./Person/PhoneType.php');
require('./Person.php');
$person = new Person();
$person->setId(1);
$person->setName("gitlib");
$phone = new \Person\PhoneNumber();
$phone->setNumber('123456');
$phone->setType(\Person\PhoneType::HOME);
$person->setPhone($phone);
$data = $person->serializeToString();
var_dump($data);
$person2 = new Person();
$person2->mergeFromString($data);
var_dump("id:".$person2->getId()." name:".$person2->getName()." phone num:".$person2->getPhone()->getNumber());
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
运行结果:
本文更新于:2019年6月,修改采用proto3和php7。
上次更新: 2022/12/01, 11:09:34