菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
3277
14

Thrift RPC 通信搭建

原创
05/13 14:22
阅读数 3298

一、先安装 Thrift 编译工具

MAC 电脑安装执行以下命令

    brew install thrift

Linux 环境下安装参考官网

官网地址:http://thrift.apache.org/download

安装完成之后

    $ thrift --version
    Thrift version 0.10.0

有以上输出说明工具安装成功

二、定义自己的Thrift 返回参数结构体

我这里定义了一个 thriftCommon.thrift 文件 这里我以 lumen框架为例 存放目录为thriftSource/thriftCommon.thrift 内容如下:

namespace php app.Library.Thrift  # 指定生成什么语言,生成文件存放的目录

// 返回结构体
struct Response {
    1: i32 code;    // 返回状态码
    2: string msg;  // 码字回提示语名
    3: string data; // 返回内容
}

// 服务体
service ThriftCommonCallService {
    // json 字符串参数  客户端请求方法
    Response invokeMethod(1:string params)
}

定义好以上文件之后使用第一步安装好的 thrift 工具来生成相应的文件

$ thrift -r --out ./ --gen php thriftSource/thriftCommon.thrift

执行该命令会在app/Library/Thrift目录生成ThriftCommonCallService.phpTypes.php文件,这是客户端文件可以分两个项目部署,也可以在同一个项目部署,我这边因为工作需要独立部署。

三、创建一个新的客户端项目

执行以下创建命令

    $ composer create-project laravel/lumen server --prefer-dist "5.5"

把第二步生成的客户端的两个文件拷贝到 app/Library/Thrift目录 如图:

file

四、服务端的实现

安装第三方使用包

$ composer require apache/thrift

使用 thrift 命令生成服务端代码

    $ thrift -r --out ./ --gen php:server thriftSource/thriftCommon.thrift

执行该命令会在app/Library/Thrift目录生成ThriftCommonCallService.phpTypes.php文件 打开 ThriftCommonCallService.php文件我们需要实现里面的接口ThriftCommonCallServiceIf 接下来我们建立实现文件 app/Library/Rpc/Server.php

<?php
namespace App\Library\Rpc;

use App\Library\Thrift\ThriftCommonCallServiceIf;
use App\Library\Thrift\Response;

class Server implements ThriftCommonCallServiceIf
{
    /**
     * 实现 socket 各个service 之间的转发
     * @param string $params
     * @return Response
     * @throws \Exception
     */
    public function invokeMethod($params)
    {
         // 转换字符串 json
         $input = json_decode($params, true);
         // 自己可以实现转发的业务逻辑
        ...

        $response = new Response();
        $response->code = 200;
        $response->msg = '';
        $response->data = json_encode($input);
        return $response;
    }

建立控制器实现服务端 端口启动 app/Http/Controllers/SocketController.php

<?php
namespace App\Http\Controllers;

use App\Library\Rpc\Server;
use app\Library\Thrift\Response;
use app\Library\Thrift\ThriftCommonCallServiceProcessor;
use Illuminate\Http\Request;
use Thrift\Exception\TException;
use Thrift\Factory\TBinaryProtocolFactory;
use Thrift\Factory\TTransportFactory;
use Thrift\Server\TServerSocket;
use Thrift\Server\TSimpleServer;
use Thrift\TMultiplexedProcessor;

class SocketController extends Controller
{
    /**
     * 启动 socket 连接
     */
    public function server()
    {
        try {
            $thriftProcessor = new ThriftCommonCallServiceProcessor(new Server());
            $tFactory = new TTransportFactory();
            $pFactory = new TBinaryProtocolFactory(true, true);
            $processor = new TMultiplexedProcessor();
            // 注册服务
            $processor->registerProcessor('thriftCommonCallService', $thriftProcessor);

            // 监听开始
            $transport = new TServerSocket('127.0.0.1', 9999);
            $server = new TSimpleServer($processor, $transport, $tFactory, $tFactory, $pFactory, $pFactory);
            $server->serve();
        } catch (TException $te) {
            app('log')->error('socket 服务启动失败', ['content' => $te->getMessage()]);
        }
    }

建立访问路由或php artisan启动命令

// 访问路由
$router->get('/rpc/server', 'SocketController@server');

建立php artisan文件 目录 app/Console/Commands/RpcServer.php

 <?php
/**
 * Created by PhpStorm.
 */

namespace App\Console\Commands;

use App\Http\Controllers\SocketController;
use Illuminate\Console\Command;

class RpcServer extends Command
{
    /**
     * 控制台命令 signature 的名称。
     *
     * @var string
     */
    protected $signature = 'server:rpc';

    /**
     * 控制台命令说明。
     *
     * @var string
     */
    protected $description = 'rpc 服务';

    protected static $socketController;

    /**
     * rpcServer constructor.
     * @param SocketController $socketController
     */
    public function __construct(SocketController $socketController)
    {
        parent::__construct();
        self::$socketController = $socketController;
    }

    /**
     * 执行控制台命令。
     *
     * @return mixed
     */
    public function handle()
    {
        self::$socketController->server();
    }
}

app/Console/Kernel.php注册

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;
use App\Console\Commands\RpcServer;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        RpcServer::class
    ];

到此服务端实现已全部完成 接下来实现客户端并成功与服务端通信

五、客户端的实现 (以第三步创建的项目为例继续说明)

安装第三方使用包

$ composer require apache/thrift

建立文件 app/Library/Tools/Socket.php

<?php
namespace App\Library\Tools;

use app\Library\Thrift\ThriftCommonCallServiceClient;
use Thrift\Protocol\TBinaryProtocol;
use Thrift\Protocol\TMultiplexedProtocol;
use Thrift\Transport\TBufferedTransport;
use Thrift\Transport\TSocket;

class Socket
{
    // 保存对象实例化
    private $_instance;

    // 保存服务连接池
    private static $client = [];

    // 配置文件
    private $config = [];

    private function __construct($type)
    {
        $config = [
            'erp' => [
                'host' => env('ERP_RPC_HOST'),
                'port' => env('ERP_RPC_PORT')
            ]
        ];
        $this->config = $config[$type];
    }

    /**
     * 连接服务
     * @param string $name  调用的方法名
     * @param array $args   1、参数数组 2、具体哪个方法名  3、所属的 Service 名称
     * @return bool
     */
    public static function __callStatic($name, $args)
    {
        if (substr($name, 0, 8) != 'SocketTo') {
            return false;
        }

        $type = strtolower(substr($name, 8));
        // 实例化操作
        if (!isset(self::$client[$type])) {
            self::$client[$type] = new self($type);
        }

        return self::$client[$type]->invoke($args);
    }

    private function invoke($args)
    {
        try {
            $socket = new TSocket($this->config['host'], $this->config['port']);
            $socket->setRecvTimeout(50000);
            $socket->setDebug(true);
            $transport = new TBufferedTransport($socket, 1024, 1024);
            $protocol = new TBinaryProtocol($transport);
            $thriftProtocol = new TMultiplexedProtocol($protocol, 'thriftCommonCallService');
            $client = new ThriftCommonCallServiceClient($thriftProtocol);
            $transport->open();
            // 拼装参数与类型
            $data = [
                'params' => $args[0],
                'methodName' => $args[1],
                'serviceName' => $args[2]
            ];
            $result = $client->invokeMethod(json_encode($data));
            $result->data = json_decode($result->data, true);
            $transport->close();
            return $result;
        } catch (\TException $Te) {
            app('log')->error('服务连接失败 ', ['host' => $this->config, 'methodName' => $args[1], 'content' => $Te->getMessage()]);
            return ['host' => $this->config, 'methodName' => $args[1], 'content' => $Te->getMessage()];
        }
    }
}

建立控制器来调用 并配置路由方问

<?php
namespace App\Http\Controllers;

use App\Library\Tools\Socket;
use Illuminate\Http\Request;

class ClientController extends Controller
{
    public function client(Request $request)
    {
       return ['code' => 20000, 'data' => ['name' => 'admin', 'roles' => ['admin']]];
       //接收参数
       $param = $request->input("params");
       //调用Service
        $data = Socket::SocketToErp($param, 'login', 'LoginService');
        return response()->json($data);
    }

以上就是实现客户端与服务端通信的内容,如有不懂可留言一块讨论^_^

发表评论

0/200
3277 点赞
14 评论
收藏
为你推荐 换一批