利用 Swoole 原生的 onReceive 回调

think-swoole 中,如果你不想把 RPC 逻辑混入全局的 swoole.receive 事件中,最直接、最高效的做法是利用 Swoole 原生的 onReceive 回调,在 config/swoole.php 的多端口监听 (listen) 中直接闭包绑定

这种做法属于“物理隔离”,RPC 的数据流完全不经过 TP6 的事件分发,性能反而更好。

以下是具体的改造方案:

1. 彻底改造 config/swoole.php

我们直接在 listen 配置中,利用 callbacks 参数绑定 Swoole 原生的 receive 事件。

php

<?php
// config/swoole.php
use app\common\rpc\RpcDispatcher;

return [
    'server' => [
        'host'      => '0.0.0.0',
        'port'      => 80, // Web 端口
        'mode'      => SWOOLE_PROCESS,
        'sock_type' => SWOOLE_SOCK_TCP,
        'options'   => [
            'worker_num' => swoole_cpu_num(),
        ],
        // 🌟 核心:在此处直接接管 TCP 接收
        'listen' => [
            [
                'host'      => '0.0.0.0',
                'port'      => 9502, // RPC 专门端口
                'sock_type' => SWOOLE_SOCK_TCP,
                'options'   => [
                    'open_eof_check' => true,
                    'package_eof'    => "\r\n",
                ],
                // 🚀 不走 TP6 事件,直接绑定 Swoole 原生回调
                'callbacks' => [
                    \Swoole\Constant::EVENT_RECEIVE => function ($server, $fd, $reactorId, $rawData) {
                        // 1. 实例化或从容器中获取调度器
                        /** @var RpcDispatcher $dispatcher */
                        $dispatcher = app(RpcDispatcher::class);
                        
                        // 2. 调度并解析
                        $responsePayload = $dispatcher->dispatch($rawData);
                        
                        // 3. 直接发送回客户端
                        $server->send($fd, $responsePayload);
                    }
                ]
            ],
        ],
    ],
    // 其他配置保持默认...
];

请谨慎使用此类代码。

2. 移除旧的事件监听(清理工作)

既然不使用事件监听了,你需要做两件事来保持项目干净:

  1. 删除文件:可以安全删除 app\listener\RpcReceiveListener.php

  2. 清理配置:检查 app\event.php,把之前加在 swoole.receive 里的配置删掉,恢复原样:

    php

    'listen' => [
        // 'swoole.receive' => [...] <- 删掉这行
    ],
    

    请谨慎使用此类代码。

3. 解析器 RpcDispatcher.php 保持不变

上一步创建的 app\common\rpc\RpcDispatcher.php 代码完全不需要修改。因为它只负责接收字符串、解析、调用、返回字符串,和底层是用事件还是用原生回调毫无关系(这也是高内聚低耦合的好处)。


💡 为什么这种方案更推荐?

  1. 零干扰:传统的 swoole.receive 事件是全局的。如果你的 Web 服务也用到了 WebSocket 或者其他 TCP 长连接,全局事件会收到所有端口的数据,你必须在里面写 if ($port === 9502) 去过滤 [1]。而现在的方案让 9502 端口的数据在底层就独立处理。

  2. 性能更高:不走 TP6 的 Event::trigger() 意味着少了一层框架的动态动态解析和观察者遍历,TCP 数据直达你的 RpcDispatcher,执行效率更高。

  3. 结构清晰:RPC 的协议配置(EOF、端口)和它的核心接收逻辑都在 config/swoole.php 的同一个数组里,代码聚合度极高。

你现在可以重启 php think swoole 服务测试一下,客户端的同步/异步调用依然可以完美无缝运行。