Thrift RPC 通信搭建
一、先安装 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.php
与Types.php
文件,这是客户端文件可以分两个项目部署,也可以在同一个项目部署,我这边因为工作需要独立部署。
三、创建一个新的客户端项目
执行以下创建命令
$ composer create-project laravel/lumen server --prefer-dist "5.5"
把第二步生成的客户端的两个文件拷贝到
app/Library/Thrift
目录 如图:
四、服务端的实现
安装第三方使用包
$ composer require apache/thrift
使用
thrift
命令生成服务端代码
$ thrift -r --out ./ --gen php:server thriftSource/thriftCommon.thrift
执行该命令会在
app/Library/Thrift
目录生成ThriftCommonCallService.php
与Types.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);
}
以上就是实现客户端与服务端通信的内容,如有不懂可留言一块讨论^_^
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: