最近用swoole framework开发个项目,想实现远程接口调用RPC,无奈swoole框架坑点太多,资料又少的可怜,只能自己研究。
利用swoole框架的RPCServer类 实现服务端,RPC类实现客户端。
实现步骤如下:
服务端
在examples/ 目录下创建
rpc_server.php
PHP代码
<?php
define('DEBUG', 'on');
define('WEBPATH', realpath(__DIR__ . '/../'));
require_once dirname(__DIR__) . '/libs/lib_config.php';
use Swoole\Protocol\RPCServer;
//设置PID文件的存储路径
Swoole\Network\Server::setPidFile(__DIR__ . '/rpc_server.pid');
/**
* 显示Usage界面
* php app_server.php start|stop|reload
*/
Swoole\Network\Server::start(function ()
{
$AppSvr = new RPCServer;
$AppSvr->setLogger(new \Swoole\Log\EchoLog(true)); //Logger
/**
* 注册一个自定义的命名空间到SOA服务器
* 默认使用 apps/classes
*/
// $AppSvr->addNameSpace('App', WEBPATH . '/apps/models');
// $AppSvr->addNameSpace('App', WEBPATH . '/apps/models');
// $AppSvr->addNameSpace('BL', __DIR__ . '/class');
/**
* IP白名单设置
*/
$AppSvr->addAllowIP('127.0.0.1');
$AppSvr->addAllowIP('127.0.0.2');
/**
* 设置用户名密码
*/
$AppSvr->addAllowUser('rpcname', 'rpc@123456');
Swoole\Error::$echo_html = false;
$server = Swoole\Network\Server::autoCreate('0.0.0.0', 8888);
$server->setProtocol($AppSvr);
//$server->daemonize(); //作为守护进程
$server->run(
array(
//TODO: 实际使用中必须调大进程数
'worker_num' => 4,
'max_request' => 5000,
'dispatch_mode' => 3,
'open_length_check' => 1,
'package_max_length' => $AppSvr->packet_maxlen,
'package_length_type' => 'N',
'package_body_offset' => \Swoole\Protocol\RPCServer::HEADER_SIZE,
'package_length_offset' => 0,
)
);
});
在 apps/classes/ 目录下创建 RPCApi.php
<?php
namespace App;
/**
* RPC Server 接口
*
* @author 郭志强
* @return void
* @throws Exception
*
*/
class RPCApi
{
/**
* 暂无说明
*
* @author 郭志强
* @return void
* @throws Exception
* @access public
*/
public static function api(array $condition)
{
$default = [
//model名字
'model' => '',
//方法名
'action' => '',
//参数
'param' => [],
];
$condition = array_merge($default, $condition);
if (!$condition['model']) {
return "Error Model Not Found ";
}
if (!$condition['action']) {
return "Error Action Not Found ";
}
$action = $condition['action'];
if ($condition['param']) {
return model($condition['model'])->$action($condition['param']);
}
return model($condition['model'])->$action();
}
}
nohup php /var/www/examples/rpc_server.php start </dev/null &>/dev/null &
客户端
在 apps/classes/ 目录下创建
RPCClient.php
代码
<?php
namespace App;
use Swoole;
/**
* RPC client 接口
*
* @author 郭志强
* @return void
* @throws Exception
*
*/
class RPCClient
{
/**
* API
*
* @author 郭志强
* @return void
* @throws Exception
* @param namespace:空间名称,如"App\\Test::hello" ,hello为方法 。param传参
* @access public
*/
public static function api( array $condition)
{
$default = [
'namespace' => "App\\RPCApi::api",
'param' => [],
];
$condition = array_merge($default,$condition);
if (!$condition['namespace'] || empty($condition['param'])) {
return ;
}
$client = Swoole\Client\RPC::getInstance();
// //$client->setEncodeType(false, true);
// // $client->putEnv('app', 'test');
$client->auth('rpcname', 'rpc@123456');//认证账号和密码
$client->addServers(array('host' => '127.0.0.1', 'port' => 8888));
$ret = $client->task($condition['namespace'], [$condition['param']]);
$client->wait(0.5); //500ms超时
unset($client);
return $ret->data;
}
}
Test.php
代码
<?php
namespace App\Model;
use Swoole;
class Test extends Swoole\Model
{
/**
* 表名
* @var string
*/
public $table = 'a';
function demo($data)
{
return $data;
}
}
测试代码
修改 apps/controllers/Page.php
代码
<?php
namespace App\Controller;
use Swoole;
use App\Base;
use App\RPCClient;
class Home extends Base
{
public function __construct($swoole)
{
parent::__construct($swoole);
}
public function index()
{
$default = [
'namespace' => "App\\RPCApi::api",
'param' => ['model'=>'Test','action'=>'demo','param'=>['a'=>'bd']],
];
echo "<pre>";
var_dump( RPCClient::api($default));
echo "</pre>";
}
}
启动客户端程序
nohup php /var/www/examples/app_server.php start </dev/null &>/dev/null &
访问
http://xxxxx/page/index
输出
array(1) {
["a"]=>
string(2) "bd"
}
证明成功
针对服务端和客户端代码修改不生效的问题,则由SWOOLE特点决定,需要热部署。具体实现热部署步骤,可参考 http://blog.csdn.net/guyan0319/article/details/73656977。