thrift的使用中一般是一个Server对应一个Processor和一个Transport,如果有多个服务的话,那必须要启动多个Server,占用多个端口,这种方式显然不是我们想要的,所以thrift为我们提供了复用端口的方式,通过监听一个端口就可以提供多种服务,这种方式需要用到两个类:TMultiplexedProcessor和TMultiplexedProtocol。
创建 2 个 Laravel 项目,thrift-server (服务端) 和 thrift-client (客户端)
testServer.thrift:
namespace php Rpc.Test
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
DIVIDE = 4
}
exception InvalidOperation {
1: i32 whatOp,
2: string why
}
service Calculator {
double calculate(1:double num1, 2:double num2, 3:Operation op) throws (1:InvalidOperation ouch),
string echoString(1: string str) ,
}
service Echo {
string echo(1: string str) ,
}
每个service类对应一种服务,服务类下可有多个方法。
thrift-server根目录生成客户端类命令:
thrift -r --out ./ --gen php thriftSource/testServer.thrift
将生成的Rpc/Test文件夹剪切到thrift-client项目的Rpc目录中
在thrift-server根目录继续生成服务端类:
thrift -r --out ./ --gen php:server thriftSource/testServer.thrift
根目录创建Service目录,存放实现Calculator和Echo类的文件
Service/CalculatorService.php
<?php
/**
* 实现Calculator服务
*/
namespace Service;
use Rpc\Test\CalculatorIf;
use Rpc\Test\Operation;
use Rpc\Test\InvalidOperation;
class CalculatorService implements CalculatorIf {
/**
* @param double $num1
* @param double $num2
* @param int $op
* @return double
* @throws InvalidOperation
*/
public function calculate($num1, $num2, $op) {
switch ($op) {
case Operation::ADD:
$val = $num1 + $num2;
break;
case Operation::SUBTRACT:
$val = $num1 - $num2;
break;
case Operation::MULTIPLY:
$val = $num1 * $num2;
break;
case Operation::DIVIDE:
if ($num2 == 0) {
$io = new InvalidOperation();
$io->whatOp = $op;
$io->why = "Cannot divide by 0";
throw $io;
}
$val = $num1 / $num2;
break;
default:
$io = new InvalidOperation();
$io->whatOp = $op;
$io->why = "Invalid Operation";
throw $io;
}
return $val;
}
/**
* @param $string
*/
public function echoString($string) {
return $string;
}
}
Service/EchoService.php:
<?php
/**
* 实现Echo服务
*/
namespace Service;
use Rpc\Test\EchoIf;
class EchoService implements EchoIf {
/**
* @param $string
*/
public function echo($string) {
return $string;
}
}
thrift-server服务端控制器:
<?php
/**
* 服务端控制器
*/
namespace App\Http\Controllers;
use Rpc\Test\CalculatorProcessor;
use Rpc\Test\EchoProcessor;
use Service\CalculatorService;
use Service\EchoService;
use Illuminate\Http\Request;
use Thrift\Protocol\TBinaryProtocol;
use Thrift\TMultiplexedProcessor;
use Thrift\Transport\TBufferedTransport;
use Thrift\Transport\TPhpStream;
use Thrift\Exception\TException;
class ServerController extends Controller
{
/**
* 多个服务
* @param Request $request
*/
function handleManyRequest(Request $request) {
try{
header('Content-Type', 'application/x-thrift');
// 初始化多个服务提供者handle
$calculatorhandler = new CalculatorService();
$echohandler = new EchoService();
$multiplexedProcessor = new TMultiplexedProcessor();
// 创建多个服务Processor
$calculatorProcessor = new CalculatorProcessor($calculatorhandler);
$echoProcessor = new EchoProcessor($echohandler);
// 将服务注册到TMultiplexedProcessor中
$multiplexedProcessor->registerProcessor("calculator", $calculatorProcessor);
$multiplexedProcessor->registerProcessor("echo", $echoProcessor);
// 初始化数据传输方式transport
$transport = new TBufferedTransport(new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W));
// 利用该传输方式初始化数据传输格式protocol
$protocol = new TBinaryProtocol($transport, true, true);
// 开始服务
$transport->open();
$multiplexedProcessor->process($protocol, $protocol);
$transport->close();
} catch (TException $tx) {
print 'TException: '.$tx->getMessage()."\n";
}
}
}
配置post方式路由
Route::post('/rpc/server', 'ServerController@handleManyRequest');
配置虚拟主机 8081 端口监听thrift-server服务,80端口监听thrift-client服务
thrift-client客户端控制器:
<?php
/**
* 客户端控制器
*/
namespace App\Http\Controllers;
use Rpc\Test\Operation;
use Rpc\Test\CalculatorClient;
use Rpc\Test\EchoClient;
use Illuminate\Http\Request;
use Thrift\Protocol\TBinaryProtocol;
use Thrift\Protocol\TMultiplexedProtocol;
use Thrift\Transport\THttpClient;
use Thrift\Transport\TBufferedTransport;
use Thrift\Exception\TException;
class ClientController extends Controller
{
/**
* 多服务
* @param Request $request
*/
function handleManyRequest(Request $request) {
try{
// 定义连接
$socket = new THttpClient('127.0.0.1', 8081, '/rpc/server');
// 创建transport
$transport = new TBufferedTransport($socket, 1024, 1024);
// 基于Transport创建Protocol
$protocol = new TBinaryProtocol($transport);
// 创建Client调用服务接口的方法
$calculatorClient = new CalculatorClient(new TMultiplexedProtocol($protocol, "calculator"));
$echoClient = new EchoClient(new TMultiplexedProtocol($protocol, "echo"));
// 开启
$transport->open();
// 调用接口方法
$sum = $calculatorClient->calculate(1, 2, Operation::ADD);
print "calculator service -> calculate function -> 1+2=$sum </br>";
$test = $calculatorClient->echoString('this it test');
print "calculator service -> echoString function -> echoString:$test </br>";
$echoString = $echoClient->echo('echo method');
print "echo service -> echo function -> echo:$echoString\n\r";
$transport->close();
} catch (TException $tx) {
print 'TException: '.$tx->getMessage()."\n";
}
}
}
由此可客户端可调用服务端的方法,实现通讯:
注意:
1、根目录新建目录需配置composer.json中的psr-4
2、取消http/kernel.php中web中间件内容