一、先安裝 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);
}
以上就是實現客戶端與服務端通訊的內容,如有不懂可留言一塊討論^_^