TP6+Swoole4 SOCKET事件处理

2,947 阅读1分钟

上一篇文章中讲配置的时候其中的一个socket配置handler事件处理为app\webscoket\Manager 类.下面来看下此类中需要完成那些方法

socket监听事件

app\event.php

return [
    'listen' => [
        'swoole.workerStart' => [\app\websocket\SwooleWorkerStart::class],//socket启动事件
        'swoole.workerStop'  => [],//socket停止事件
        'swoole.workerError' => [],//socket发生错误事件
        'swoole.workerExit'  => [],//仅在异步重启后执行事件
    ]
];

SwooleWorkerStart 类内部结构

<?php

namespace app\webscoket;

class SwooleWorkerStart
{

    public function __construct()
    {
    
    }      // 事件执行 $event 为对象think\swoole\App实例化后的结果
      public function handle($event): void
      {
           if ($event->make('swoole.server')->worker_id === 0 && 
                $event->config->get('swoole.websocket.enable',false)) {
                //只有再0号进程上监听socket启动事件
                //并且socket已经启动了才执行事件
                //socket的ping事件
                $this->ping();
                //定时任务
                $this->timer();
           }
      }

}

app\webscoket\Manager类内部结构

swoole.php配置中的websocket.handle 一旦被重新配置,类被重写那么原本内置的事件会丢失需要自行处理

<?php

namespace app\webscoket;

use think\swoole\Websocket;
use Swoole\Websocket\Frame;

class Manager extends Websocket
{

    /** 
    * 启动事件
    * "onOpen" listener. 
    * 
    * @param int $fd 
    * @param Request $request 
    */
    public function onOpen($fd, \think\Request $request)
    {
        //可以写长连接授权的逻辑
        //授权不通过调用 $this->server->close($fd);关闭连接

        //$request->get()能获取到长连接携带的参数
        
        //登陆成功可以用push方法推送消息到前台
        //$this->server->push($fd, $data);
    }

    /** 
    * 消息接收事件
    * "onMessage" listener. 
    * 
    * @param Frame $frame 
    */
    public function onMessage(Frame $frame)
    {
        //$frame->fd 为当前连接唯一值
        //$frame->data 为当前消息内容
        //可以根据消息内容做出对应的消息处理逻辑
        //消息的内容可如下
        //{"type":"test","data":{"message":"你好呀"}}
        //然后根据type可调用不同的事件或者方法来处理消息
    }

    /** 
    * 关闭事件
    * "onClose" listener. 
    * 
    * @param int $fd 连接fd
    * @param int $reactorId 线程id
    */
    public function onClose($fd, $reactorId)
    {
        //这里主要处理某个连接关闭后的事件,告知其他人或者修改数据库让当前连接对应的用户下线
    }
}

处理Ping

思路就是启动一个定时器不停的监听当前连接的用户是否再ping的有效时间内刷新过ping如果没有那就调用app('swoole.server')->close($fd)来关闭它

此方法写在 SwooleWorkerStart 类中

use Swoole\Timer;

protected function ping()
{
    
    Timer::tick(1500, function (int $timer_id) {
        /** @var Swoole\Server $server*/        
        $server = app('swoole.server');
        foreach ($server->connections as $fd) {            
            if ($server->isEstablished($fd)) {
                //可以利用内存数据库把$fd相关的用户信息和连接过期时长记录下来
                //然后来判断是否要关闭这个连接
                //关闭: $server->close($fd);
            }
        }
    });
}

Swoole\Server->isEstablished()

检查是否是一个有效的websocket连接