Protobuf 简介

protobuf(Protocol buffers)是谷歌出品的跨平台、跨语言、可扩展的数据传输及存储的协议,是高效的数据压缩编码方式之一。

Protocol buffers 在序列化数据方面,它是灵活的,高效的。相比于 XML 来说,Protocol buffers 更加小巧,更加快速,更加简单。一旦定义了要处理的数据的数据结构之后,就可以利用 Protocol buffers 的代码生成工具生成相关的代码。甚至可以在无需重新部署程序的情况下更新数据结构。只需使用 Protobuf 对数据结构进行一次描述,即可利用各种不同语言或从各种不同数据流中对你的结构化数据轻松读写。

Protocol buffers 很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

此外,Protobuf由于其在内网高效的数据交换效率,是被广泛应用于微服务的,在谷歌的开源框架grpc即是基于此构建起来的。

php-protobuf安装

由于protobuf原生并不支持php,所以php如果使用pb则需要安装相应扩展。

pecl install protobuf

环境中需要有protoc编译器,下载安装方式:

$ wget https://github.com/google/protobuf/releases/download/v2.5.0/protobuf-2.5.0.tar.gz$ tar zxvf protobuf-2.5.0.tar.gz$ cd protobuf-2.5.0$ ./configure --prefix=/usr/local/protobuf$ sudo make $ sudo  make install

验证安装成功:

$ /usr/local/protobuf/bin/protoc  --versionlibprotoc 2.5.0

php-protobuf安装成功

php --ri protobuf

安装lumen和google/protobuf依赖

lumen new rpc
lumen new rpc命令相当于composer create-project laravel/lumen rpc
composer require google/protobuf

composer.json下添加classmap:

{    "classmap": [        "protobuf/"    ]}

ok,准备工作都已做好了。

自己做一个demo

在代码目录下创建一个protobuf文件夹mkdir protobuf

进入该目录,创建一个文件searchRequest.proto

syntax = "proto3";message SearchRequest {    string query = 1;    int32 page_number = 2;    int32 result_per_page = 3;    enum Corpus {        UNIVERSAL = 0;        WEB = 1;        IMAGES = 2;        LOCAL = 3;        NEWS = 4;        PRODUCTS = 5;        VIDEO = 6;    }    Corpus corpus = 4;}

????此处很重要????

composer.json下添加classmap,否则将无法侦测到对应class
{   "classmap": [       "protobuf/"   ]}

在命令行下运行:protoc --proto_path=protobuf/ --php_out=protobuf/ protobuf/searchRequest.proto && composer dump-autoload

现在你看到的代码目录,应该是这样的:

现在,我们需要的请求类已经得到了,现在看看如何使用它!

使用

在web.php创建一个路由

$router->get('testp', 'ExampleController@testProtobuf');

ExampleController下添加:

    public function testProtobuf()    {        // require_once base_path('protobuf/SearchRequest.php');        $request = new \SearchRequest();        $request->setPageNumber(67);        dd($request->getPageNumber());    }

如果正常打印出67这个数字,就表示该类可以用,恭喜你已经成功完成了一个请求类的创建。

Go deeper

现在,看一下生成的SearchRequest都有哪些方法:

array:16 [▼  0 => "__construct"  1 => "getQuery"  2 => "setQuery"  3 => "getPageNumber"  4 => "setPageNumber"  5 => "getResultPerPage"  6 => "setResultPerPage"  7 => "getCorpus"  8 => "setCorpus"  9 => "clear"  10 => "discardUnknownFields"  11 => "serializeToString"  12 => "mergeFromString"  13 => "serializeToJsonString"  14 => "mergeFromJsonString"  15 => "mergeFrom"]

这里面带有set前缀的方法,都是设定对应字段的,带有get的,都是从buffer中获取值的,里面的SerializeToString,建议阅读官方文档,里面有对应的合理的解释。

和grpc的结合

composer install grpc/grpc

定义Service,这一个需要在client和server两端都要完成

service RouteGuide {   rpc GetFeature(Point) returns (Feature) {}   rpc RecordRoute(stream Point) returns (RouteSummary) {}   rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}}message Point {  int32 latitude = 1;  int32 longitude = 2;}

protoc生成对应的Service实例。

创建一个client

$client = new Routeguide\RouteGuideClient('localhost:50051', [    'credentials' => Grpc\ChannelCredentials::createInsecure(),]);

调用RPC服务

$point = new Routeguide\Point();$point->setLatitude(409146138);$point->setLongitude(-746188906);list($feature, $status) = $client->GetFeature($point)->wait();

grpc更多实现,请参阅官方文档、快速指南