简介
Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。
如果要看序列号解析原理也可参考:https://www.cnblogs.com/naci/p/5341433.html
客观的说:感觉protobuf对php支持的不是很好,写一些比较复杂的数据结构,还是比较麻烦的。也有可能是自己的不足吧。
安装protobuf
进入网址:https://github.com/protocolbuffers/protobuf/releases
下载对应自己需要的安装包。进行安装
进入解压的安装包,执行以下命令:
./configure
make && make install
执行以上命令之后,执行下面的命令 查看是否安装成功,如果没报错,会显示protobuf的版本
protoc --version
定义proto文件
例如:hello.proto
syntax = "proto3";
package lm;
message helloworld
{
int32 id = 1; // ID
string str = 2; // str
int32 opt = 3; // optional field
}
注意:这里采用的是proto3的语法,和proto2不太一样,required
和optional
的限定已经没有了,所有的字段都是可选的。proto3相比proto2有什么区别
编译生成php文件
使用上面安装成功的protobuf进行编译proto文件
protoc hello.prot --php_out=./
解释:
--php_out :编译输出成php文件
--python_out :编译输出成python文件
这时会在当前目录下,生成一个GPBMetadata的文件夹和Lm的文件夹,此时查看lm文件夹下的helloworld.php文件
阅读下里面的代码,发现它use了Google\Protobuf
下的类,这是一个PHP库,可以去下载:
https://github.com/google/protobuf/tree/master/php/src/Google/Protobuf
也可以用composer
引入到项目中,推荐用composer引入,因为composer会帮你自动生成Autoloader
composer require google/protobuf
采用composer方式引入google/protobuf
之后,项目中会出现一个vendor
目录。在自己的代码中include vendor
下的autoload.php
,以及刚才生成的helloworld.php
文件,就可以进行二进制的读写了
测试二进制读写
写入二进制文件
<?php
include 'vendor/autoload.php';
include 'GPBMetadata/Hello.php';
include 'Lm/Hello.php';
$from = new \Lm\helloworld();
$from->setId(1);
$from->setStr('foo bar, this is a message');
$from->setOpt(29);
$data = $from->serializeToString();
file_put_contents('data.bin', $data);
读取二进制文件
<?php
include 'vendor/autoload.php';
include 'GPBMetadata/Hello.php';
include 'Lm/Hello.php';
$data = file_get_contents('data.bin');
$to = new \Lm\helloworld();
$to->mergeFromString($data);
echo $to->getId() . PHP_EOL;
echo $to->getStr() . PHP_EOL;
echo $to->getOpt() . PHP_EOL;
其实写到这里,你可能会发现读取很麻烦,如果参数很多岂不是要一个个打印出来,所以我最后用是python进行解析的,一个方法就自动全部读取了。
python进行解析二进制文件
编写test.py文件
# -*- coding: utf-8 -*-
import hello_pb2
import sys
helloworld = hello_pb2.helloworld()
f = open(sys.argv[1],'rb')
helloworld.ParseFromString(f.read())
print helloworld
解释:
hello_pb2:为 protoc hello.proto --python_out=./ 命令编译所得
执行该python文件的命令(后面的参数为data二进制文件的路径):python test.py ./data
以上就是整个作者使用的过程
*看到有人说安装php的protobuf扩展可以解决多个参数一次性打印问题
在这里我也写出方法,但是本人自己安装之后,在执行文件会报错,希望后来者给出建议
一、安装php的protobuf扩展
进入php的目录的bin目录下,一般都会发现有pecl命令,然后执行以下命令
./pecl install protobuf
按照提示,在php.ini文件中加入protobuf的扩展
重启php即可
二、安装完php扩展,读写二进制文件
//写入
public function encode($data){
$fields = $this->fields();
foreach ($fields as $key => $_item) {
$field_name = $_item['name'];
if(isset($data[$field_name])) {
$this->set($key, $data[$field_name]);
}
}
try {
$packed = $this->serializeToString();
} catch (\Exception $ex) {
$data['fields'] = $fields;
$data['error'] = $ex->getMessage();
writeLog($data, 'encode_new_pb_failed');
$packed = '';
}
return $packed;
}
//读取
public function decode($packed){
try {
$this->parseFromString($packed);
} catch (\Exception $ex) {
writeLog($ex->getMessage(), 'decode_new_pb_failed');
}
$data = array();
$fields = $this->fields();
foreach ($fields as $key => $_item) {
$field_name = $_item['name'];
$data[$field_name] = $this->get($key);
}
return $data;
}
基于安装扩展之后的操作,作者并没有成功,也没时间去调试,希望大家借鉴下即可。勿喷