CentOS下grpc的go服务端+PHP客户端实现
[scode type="yellow"]首先声明,截至文章日期为止,并没有发布php的grpc服务端(据说是因为php不是常驻内存的原因),所以使用golang的服务端代替,反正不影响使用就行,另外如果你喜欢其他语言也可以,例如node做server。[/scode]
一、首先安装golang并设置环境变量
安装方法看《CentOS安装/更新Golang 1.9以上版本》,最好安装1.9及以上的版本,然后设置变量,如下:
vi /etc/bashrc
内容
export GOPATH=/home/Go
export GOROOT=/home/go
export PATH=$PATH:$GOROOT/bin
使环境变量生效
source /etc/bashrc
创建GOHOME目录
mkdir /home/Go
二、安装golang grpc
golang protobuf 库
go get -u github.com/golang/protobuf/proto
protoc --go_out 工具
go get -u github.com/golang/protobuf/protoc-gen-go
如果可以翻墙:
go get google.golang.org/grpc
否则:
[scode type="share"]
mkdir -p $GOPATH/src/golang.org/x
cd $GOPATH/src/golang.org/x
git clone https://github.com/golang/net.git --depth 1
git clone https://github.com/golang/text.git --depth 1
git clone https://github.com/golang/sys.git --depth 1
建立相关目录,进入目录
mkdir -p $GOPATH/src/google.golang.org/
cd $GOPATH/src/google.golang.org
git clone https://github.com/google/go-genproto.git genproto --depth 1
从Github上克隆grpc仓库
git clone https://github.com/grpc/grpc-go.git grpc
安装仓库
cd $GOPATH/src/
go install google.golang.org/grpc
[/scode]
三、运行go grpc
运行go grpc服务端和客户端
1、服务端
编译服务端
cd $GOPATH/src/google.golang.org/grpc/examples/helloworld/greeter_server
go build -o greeter_server main.go
运行服务端
./greeter_server &
2、客户端
编译客户端
cd $GOPATH/src/google.golang.org/grpc/examples/helloworld/greeter_client
go build -o greeter_client main.go
运行客
./greeter_client
出现如下信息证明成功
[scode type="share"]2019/01/08 18:18:54 Greeting: Hello world[/scode]
四、安装php grpc客户端
[post cid="201" /]
五、创建proto文件
创建helloworld.proto文件,内容如下:
syntax = "proto3";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
生成相关包文件
protoc --proto_path=/var/www/html/mysite --php_out=/var/www/html/mysite --grpc_out=/var/www/html/mysite --plugin=protoc-gen-grpc=/var/www/html/grpc/bins/opt/grpc_php_plugin /var/www/html/mysite/helloworld.proto
此时目录下会生成 GPBMetadata 和 Helloworld 两个目录
六、创建composer文件
创建composer.json文件,内容如下:
{
"name": "grpc/grpc-demo",
"description": "gRPC example for PHP",
"require": {
"grpc/grpc": "^v1.3.0",
"google/protobuf": "^v3.3.0"
},
"autoload": {
"psr-4": {
"GPBMetadata\\": "GPBMetadata/",
"Helloworld\\": "Helloworld/"
}
}
}
生成自动加载及公共类库vendor
composer install
注意:因为在composer.json里面已经指定了GPBMetadata、Helloworld的加载为止,所以composer install或者composer update之后不用单独包含这两个目录里面的类文件了,因为已经autoload自动加载。
七、php客户端调用
例子 1:
<?php
require dirname(__FILE__). '/vendor/autoload.php';
// 50051端口随意是什么都可以,不过要与服务端监听的端口一致
$client = new Helloworld\GreeterClient('127.0.0.1:50051', [
'credentials' => Grpc\ChannelCredentials::createInsecure(),
]);
$request = new Helloworld\HelloRequest();
$request->setName('hahahaha');
list($reply, $status) = $client->SayHello($request)->wait();
echo $reply->getMessage();exit;
例子2:
proto文件
syntax = "proto3";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// 接收提交的参数
message HelloRequest {
string id = 1;
string name = 2;
}
// 为下面返回数据定义详细的格式
message Result {
int32 id = 1;
int32 age = 2;
int32 gender = 3;
string name = 4;
}
// 返回的数据
message HelloReply {
repeated Result result = 1;
}
php客户端代码
<?php
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
require dirname(__FILE__). '/vendor/autoload.php';
// 需要返回的数据
$result = array(
array (
'id' => 1,
'age' => 22,
'gender' => 1,
'name' => 'zhangsan'
),
array (
'id' => 2,
'age' => 27,
'gender' => 2,
'name' => 'lijing'
)
);
// 打开gRPC端口
$client = new Helloworld\GreeterClient('127.0.0.1:50051', [
'credentials' => Grpc\ChannelCredentials::createInsecure(),
]);
// proto使用repeated类型数据格式,那么需要这个类,repeated类型数据格式主要是适用与重复出现的数据,例如N个用户的列表
$arr = new RepeatedField(GPBType::MESSAGE, Helloworld\Result::class);
// 这个是我自己定义的,为了偷懒,并不一定适用所有情景,你也可以使用SetXxx()、GetXxx()来代替
function func($key, $type = 'set')
{
$key = explode('_', $key);
$key = implode('', array_map('ucfirst', $key));
return $type . ucfirst($key);
}
foreach ($result as $info) {
$res = new \Helloworld\Result();
foreach ($info as $key => $val) {
$func = func($key, 'set');
$res->$func($val);
}
$arr[] = $res;
}
$request = new \Helloworld\HelloRequest();
$request->setId(1);
$request->setName('zhangsan');
list($reply, $status) = $client->SayHello($request)->wait();
// 提交给服务端
$reply->setResult($arr);
if (is_object($reply) && $status->code == 0) {
$list = array();
foreach ($reply->getResult() as $val) {
$info = array();
foreach (array_keys($result[0]) as $key) {
$func = func($key, 'get');
$info[$key] = $val->$func();
}
$list[] = $info;
}
echo '
';print_r($list);exit; } else { echo $status->details; } [1]: https://www.kyzy.cc/206.html
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭