gRPC(2)- PHP使用gRPC

前言

上节已经介绍了GRPC,不了解GRPC的可以先看下。
本文将讲述PHP如何使用GRPC

下载Protoc

上节讲了GPRC使用协议缓冲区,需要使用protoc特殊的 gRPC 插件从您的 proto 文件生成代码。
点击 下载地址 选择对应的平台。
我本机是windows10 x64,对应的下载链接

将下载的压缩包解压,bin文件路径加入到系统环境变量Path中
打开命令行运行

protoc --version

查看protoc版本是否运行成功
在这里插入图片描述

编写proto文件

万事开头say hello,下面写一个helloworld.proto。proto3语言指南

// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
// 定义服务
service Greeter {
  // Sends a greeting
  // 服务接口 
  // HelloRequest请求体
  // HelloReply 响应体
  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工具生成客户端代码和服务端代码

protoc --php_out=php   ./helloworld.proto
# --php_out : 指定php输出路径

执行以上命令后
会再php文件夹目录下生成以下文件
在这里插入图片描述

主要看Helloworld文件夹下的文件
响应类HelloReply.php

namespace Helloworld;

use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;

/**
 * The response message containing the greetings
 *
 * Generated from protobuf message <code>helloworld.HelloReply</code>
 */
class HelloReply extends \Google\Protobuf\Internal\Message
{
    /**
     * protoc文件定义Reply的属性Message
     * Generated from protobuf field <code>string message = 1;</code>
     */
    protected $message = '';

    /**
     * Constructor.
     *
     * @param array $data {
     *     Optional. Data for populating the Message object.
     *
     *     @type string $message
     * }
     */
    public function __construct($data = NULL) {
        \GPBMetadata\Examples\Protos\Helloworld::initOnce();
        parent::__construct($data);
    }

    /**
     * 获取响应数据,在客户端实现获取
     * Generated from protobuf field <code>string message = 1;</code>
     * @return string
     */
    public function getMessage()
    {
        return $this->message;
    }

    /**
     * 响应数据赋值,在服务端实现赋值
     * Generated from protobuf field <code>string message = 1;</code>
     * @param string $var
     * @return $this
     */
    public function setMessage($var)
    {
        GPBUtil::checkString($var, True);
        $this->message = $var;

        return $this;
    }

}

请求类HelloRequest.php

namespace Helloworld;

use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;

/**
 * The request message containing the user's name.
 *
 * Generated from protobuf message <code>helloworld.HelloRequest</code>
 */
class HelloRequest extends \Google\Protobuf\Internal\Message
{
    /**
     * Generated from protobuf field <code>string name = 1;</code>
     */
    protected $name = '';

    /**
     * Constructor.
     *
     * @param array $data {
     *     Optional. Data for populating the Message object.
     *
     *     @type string $name
     * }
     */
    public function __construct($data = NULL) {
        \GPBMetadata\Helloworld::initOnce();
        parent::__construct($data);
    }

    /**
     * 从protobuf字段生成string name = 1
     * Generated from protobuf field <code>string name = 1;</code>
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * 从protobuf字段生成string name = 1
     * Generated from protobuf field <code>string name = 1;</code>
     * @param string $var
     * @return $this
     */
    public function setName($var)
    {
        GPBUtil::checkString($var, True);
        $this->name = $var;

        return $this;
    }

}

我们在新建个客户端类,作为客户端连接的模板,后面实现时继承该类
HelloClient.php

<?php
/**
 * Created by PhpStorm.
 * User: 17208
 * Date: 2021/7/22
 * Time: 13:50
 */

namespace Helloworld;

/**
 * The greeting service definition.
 */
class HelloClient extends \Grpc\BaseStub {

    /**
     * @param string $hostname hostname
     * @param array $opts channel options
     * @param \Grpc\Channel $channel (optional) re-use channel object
     */
    public function __construct($hostname, $opts, $channel = null) {
        parent::__construct($hostname, $opts, $channel);
    }

    /**
     * 这里对应protobuf定义的服务
     * @param \Helloworld\HelloRequest $argument input argument
     * @param array $metadata metadata
     * @param array $options call options
     * @return \Grpc\UnaryCall
     */
    public function SayHello(\Helloworld\HelloRequest $argument, $metadata = [], $options = []) {
        return $this->_simpleRequest('/helloworld.Greeter/SayHello',
            $argument,
            ['\Helloworld\HelloReply', 'decode'],
            $metadata, $options);
    }
}

再新建个服务类,作为服务模板继承,用于开启服务
HelloStub.php


namespace Helloworld;


namespace Helloworld;

/**
 * The greeting service definition.
 */
class HelloStub {

    /**
     * 这里对应protobuf定义的服务
     * Sends a greeting
     * @param \Helloworld\HelloRequest $request client request
     * @param \Grpc\ServerContext $context server request context
     * @return \Helloworld\HelloReply for response data, null if if error occured
     *     initial metadata (if any) and status (if not ok) should be set to $context
     */
    public function SayHello(
        \Helloworld\HelloRequest $request,
        \Grpc\ServerContext $context
    ): ?\Helloworld\HelloReply {
        $context->setStatus(\Grpc\Status::unimplemented());
        return null;
    }

    /**
     * Get the method descriptors of the service for server registration
     *
     * @return array of \Grpc\MethodDescriptor for the service methods
     */
    public final function getMethodDescriptors(): array
    {
        return [
            '/helloworld.Greeter/SayHello' => new \Grpc\MethodDescriptor(
                $this,
                'SayHello',
                '\Helloworld\HelloRequest',
                \Grpc\MethodDescriptor::UNARY_CALL
            ),
        ];
    }

}

代码实现

准备

1.下载安装 PHP的gRPC扩展protobuf扩展
2.安装 composer 来管理和加载PHP的类库
composer.json

{
  "name": "grpc-go-php",
  "require": {
    "grpc/grpc": "^v1.3.0",
    "google/protobuf": "^v3.3.0"
  },
  "autoload":{
    "psr-4":{
      "GPBMetadata\\":"GPBMetadata/",
      "Helloworld\\":"Helloworld/"
    }
  }
}

运行composer install 加载类库

composer install

服务端服务实现

新建文件 server.php

// 引入类库
require dirname(__FILE__) . '/vendor/autoload.php';

// 定义服务类继承Helloworld\GreeterStub
class Greeter extends Helloworld\GreeterStub
{
	// 实现接口
    public function SayHello(
        \Helloworld\HelloRequest $request,
        \Grpc\ServerContext $serverContext
    ):? \Helloworld\HelloReply {
    	// 获取请求参数
        $name = $request->getName();
        // 定义一个实例响应体
        $response = new \Helloworld\HelloReply();
		// 服务逻辑实现
        $msg = "Hello ".$name;
		// 响应体返回
        $response->setMessage($msg);
        return $response;
    }
}
// 初始化并启动服务
$server = new \Grpc\RpcServer();
$server->addHttp2Port('0.0.0.0:50052');// 定义服务端口
$server->handle(new Greeter());	
$server->run();

运行

php server.php

运行效果
在这里插入图片描述

客户端请求实现

新建文件 client.php

// 引入类库
require dirname(__FILE__).'/vendor/autoload.php';

function greet($hostname, $name)
{
	// 初始化一个客户端实例
    $client = new Helloworld\GreeterClient($hostname, [
        'credentials' => Grpc\ChannelCredentials::createInsecure(),
    ]);
    // 初始化一个请求类
    $request = new Helloworld\HelloRequest();
    // 参数赋值
    $request->setName($name);
    // 请求服务
    list($response, $status) = $client->SayHello($request)->wait();
    // 响应处理
    if ($status->code !== Grpc\STATUS_OK) {
        echo "ERROR: " . $status->code . ", " . $status->details . PHP_EOL;
        exit(1);
    }
    echo $response->getMessage() . PHP_EOL;
}

$name = !empty($argv[1]) ? $argv[1] : 'world';
$hostname = !empty($argv[2]) ? $argv[2] : 'localhost:50052';
greet($hostname, $name);

在当前文件夹打开命令行窗口运行

php client.php

运行结果:
在这里插入图片描述

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值