在 think-swoole 4.0(基于 ThinkPHP 6.0)中实现自定义 RPC 服务,最优雅的方式是使用 Swoole 的 多端口监听(Server::addlistener) 功能。通过自定义服务类,你可以在同一个主进程中独立处理 RPC 请求。
以下是具体的实现步骤与代码示例:
第一步:创建自定义 Swoole 服务类
继承 think\swoole\Server 并重写 onWorkerStart 与自定义的 RPC 逻辑。
创建文件 app/swoole/RpcServer.php:
php
namespace app\swoole;
use think\swoole\Server;
use Swoole\Server as SwooleServer;
class RpcServer extends Server
{
/**
* 重写父类方法,增加端口监听
* @param SwooleServer $server
*/
public function onWorkerStart(SwooleServer $server, int $workerId)
{
// 监听额外的 9502 端口用于 RPC 服务,协议为 TCP
$rpcPort = $server->addlistener('0.0.0.0', 9502, SWOOLE_SOCK_TCP);
// 可选:设置 RPC 端口的协议,如 EOF 边界检测或 JSON 解析
$rpcPort->set([
'open_length_check' => true,
'package_length_type' => 'N',
'package_length_offset' => 0,
'package_body_offset' => 4,
'package_max_length' => 2097152,
]);
// 绑定 RPC 端口的数据接收事件
$rpcPort->on('receive', function (SwooleServer $server, $fd, $reactorId, $data) {
$this->handleRpc($server, $fd, $data);
});
// 调用父类的 onWorkerStart 保证其他常规业务(如HTTP/Websocket)正常启动
parent::onWorkerStart($server, $workerId);
}
/**
* 处理 RPC 请求逻辑
*/
protected function handleRpc(SwooleServer $server, $fd, $data)
{
// 1. 解析客户端传来的数据(假设为 JSON 格式)
$req = json_decode($data, true);
$method = $req['method'] ?? '';
$params = $req['params'] ?? [];
// 2. 路由处理并调用对应逻辑
$result = $this->dispatch($method, $params);
// 3. 返回结果给客户端
$server->send($fd, json_encode($result));
// 4. 短连接处理,处理完关闭连接
$server->close($fd);
}
/**
* 简单的服务分发逻辑
*/
protected function dispatch($method, $params)
{
// 示例:模拟用户服务
if ($method === 'getUser') {
$userId = $params['id'] ?? 0;
return [
'code' => 200,
'message' => 'Success',
'data' => ['id' => $userId, 'name' => 'ThinkSwoole']
];
}
return ['code' => 404, 'message' => 'Method Not Found'];
}
}
请谨慎使用此类代码。
第二步:修改配置文件
修改 config/swoole.php,将 server 指向你刚刚创建的自定义类:
php
return [
// 将此处替换为你自定义的服务类
'server' => '\app\swoole\RpcServer',
// 主服务器监听端口(通常处理 HTTP/WebSocket)
'host' => '0.0.0.0',
'port' => 80,
// ... 其他配置保持不变 ...
];
请谨慎使用此类代码。
第三步:启动服务
在项目根目录执行以下命令启动 Swoole:
bash
php think swoole
请谨慎使用此类代码。
启动后,主服务会监听默认端口,同时会在内部监听 9502 端口等待 RPC 客户端请求。
第四步:RPC 客户端调用示例
你可以使用任意客户端(如普通的 PHP 脚本、Go 等其他语言)通过 TCP 连接发送 JSON 数据进行测试:
php
// 简单的 PHP 客户端测试脚本
$client = new \Swoole\Client(SWOOLE_SOCK_TCP);
if (!$client->connect('127.0.0.1', 9502, 0.5)) {
die("connect failed. Error: {$client->errCode}\n");
}
// 发送 RPC 调用请求
$req = [
'method' => 'getUser',
'params' => ['id' => 1001]
];
$client->send(json_encode($req));
// 接收返回数据
echo $client->recv();
$client->close();