2019/10/17

laravel websocket状态通知


应用场景
在用户获取到消息通知、异步下载完成、权限变更等一系列需要后端能及时通知到前端的地方,基于websocket主动告知前端进行处理。

使用到技术和组件

参考文章
https://0x1.im/blog/php/redis-websocket-push.html

正常请求前后端基于http协议,由前端单项发起请求,后端返回数据。当后端有需要主动告知前端变更内容时,基于websocket发现通知。

用 PHP 的库来开一个 WebSocket 服务端口的时候,由于要保持连接,并接收的后续连接,所以服务本身是处于监听端口的状态。而程序还需要同时要订阅来自 Redis 的事件,同样也需要监听 Redis 的消息。所以两边程序都需要绑定到同一异步 EventLoop 中,否则将会被某一方堵塞而无法运行另一方。

ratchetphp/Ratchet 和 clue/reactphp-redis 都是使用了 reactphp/event-loop 作为异步处理媒介,所以可以将其结合使用。

$loop = \React\EventLoop\Factory::create();

// 启动websocket
$ws        = new \App\WebSocket\WebSocket();
$webSock   = new \React\Socket\Server("0.0.0.0:8080", $loop);
$webServer = new \Ratchet\Server\IoServer(
    new \Ratchet\Http\HttpServer(
        new \Ratchet\WebSocket\WsServer(
            $ws
        )
    ),
    $webSock
);

// 启动redis监听
$factory  = new \Clue\React\Redis\Factory($loop);
$client   = $factory->createLazyClient('redis://127.0.0.1"6379');
$channel  = 'websocket-channel';
$client->subscribe($channel);
$client->on('message', function ($channel, $msg) use ($ws) {
    $ws->onSubscribe($channel, $msg);
});

$loop->run();

实现流程

  • 1、登录成功后前端与后端websocket连接,保持连接状态。
  • 2、当用户数据改变,后端基于 laravel 事件系统通知,监听器收到事件通知后将其事件发送到 redis 推送。
  • 3、异步redis订阅收取到信息后进行组织,然后基于websocket通知给前端。