tp6+think-swoole 开发 Websocket

tp6+think-swoole 开发 Websocket

tp6+think-swoole 开发 Websocket:

环境要求:
php>=7.4
thinkphp 6 安装最新版 composer create-project topthink/think tp
think-swoole 安装 composer require topthink/think-swoole
服务器:liunx+nginx
宝塔面板管理:php swoole 扩展可通过宝塔工具进行安装


环境准备完成后修改swoole 配置文件,位置在 config/swoole.php

    'http'       => [
        'enable'     => true,
        'host'       => '0.0.0.0',
        'port'       => 9501, //修改相关端口
        'worker_num' => swoole_cpu_num(),
        'options'    => [],
    ],
    'websocket'  => [
        'enable'        => true, //改成true
        'handler'       => Handler::class,
        'ping_interval' => 25000,
        'ping_timeout'  => 60000,
        'room'          => [
            'type'  => 'table',
            'table' => [
                'room_rows'   => 8192,
                'room_size'   => 2048,
                'client_rows' => 4096,
                'client_size' => 2048,
            ],
            'redis' => [
                'host'          => '127.0.0.1',
                'port'          => 6379,
                'max_active'    => 3,
                'max_wait_time' => 5,
            ],
        ],
        'listen'        => [
        ],
        'subscribe'     => [],
    ],

启动 swoole:

提示:官方文档中 启动 php think swoole stat 会报错

将目录切换到站点根目录 使用命令
php think swoole
来启动,启动后关闭终端后swoole 也会关闭,如果想要 swoole 后台运行,请使用
nohup php think swoole &
命令来启动


前端连接:

提示:这里填写该问题的具体解决方案:

<script>
  var ws = new WebSocket("ws://127.0.0.1:9501/");
  ws.onopen = function(){
    console.log('连接成功');
  }
  ws.onmessage = function(data){
    console.log('返回数据')
    console.log(data);
  }
  ws.onclose = function(){
    console.log('连接断开');
  }
  function send()
  {
    ws.send(JSON.stringify({
      type:'test',//监听的自定义事件
      data:message//要发送的消息
    }));
  }
</script>

前端连接成功后发送消息给后端就会断开:

修改后台代码 vendor\topthink\think-swoole\src\websocket\socketio\Handler.php
原代码:

    /**
     * "onMessage" listener.
     *
     * @param Frame $frame
     */
    public function onMessage(Frame $frame)
    {
        $enginePacket = EnginePacket::fromString($frame->data);
        $this->event->trigger('swoole.websocket.Message', $enginePacket);
        $this->resetPingTimeout($this->pingInterval + $this->pingTimeout);
        switch ($enginePacket->type) {
            case EnginePacket::MESSAGE:
                $packet = Packet::fromString($enginePacket->data);
                switch ($packet->type) {
                    case Packet::CONNECT:
                        $this->onConnect($packet->data);
                        break;
                    case Packet::EVENT:
                        $type   = array_shift($packet->data);
                        $data   = $packet->data;
                        $result = $this->event->trigger('swoole.websocket.Event', new WsEvent($type, $data));
                        if ($packet->id !== null) {
                            $responsePacket = Packet::create(Packet::ACK, [
                                'id'   => $packet->id,
                                'nsp'  => $packet->nsp,
                                'data' => $result,
                            ]);
                            $this->push($responsePacket);
                        }
                        break;
                    case Packet::DISCONNECT:
                        $this->event->trigger('swoole.websocket.Disconnect');
                        $this->websocket->close();
                        break;
                    default:
                        $this->websocket->close();
                        break;
                }
                break;
            case EnginePacket::PING:
                $this->push(EnginePacket::pong($enginePacket->data));
                break;
            case EnginePacket::PONG:
                $this->schedulePing();
                break;
            default:
                $this->websocket->close();
                break;
        }
    }

前端传输发送数据:

 ws.send(JSON.stringify(['test',{
      to:'test',
      message:message//要发送的消息
    }]));

通过这种方式传输的数据,后台获取到数据以后,无法进行正确的处理,导致直接关闭了连接,所以进行如下修改

    /**
     * "onMessage" listener.
     *
     * @param Frame $frame
     */
    public function onMessage(Frame $frame)
    {
        $frameData = json_decode($frame->data);
        $this->event->trigger('swoole.websocket.'.ucfirst($frameData->type), $frameData->data);
    }

前端传输发送数据:

 ws.send(JSON.stringify({
      type:'test',//自定义监听事件
      data:message//要发送的消息
    }));

提示:不知道官方为啥要那样写,但是那样写一定有他的道理,改写底层方法终归不是好的办法,有知道的可以告知

解决站点配置了https 让其支持 wss 的配置:

在站点配置文件中添加如下代码,可使用宝塔中站点设置-》配置文件中新增如下代码

 location /websocket {
        proxy_pass 127.0.0.1:9501; 
        proxy_read_timeout 60s;
        proxy_http_version 1.1;
        proxy_set_header X-Client-IP $remote_addr;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'Upgrade';
    } 

前端连接

	new WebSocket("wss://127.0.0.1/websocket");

创建后台监听文件

 php think make:listener WsConnect  //监听连接
 php think make:listener WsClose  //监听关闭
 php think make:listener WsTsst  //监听自定事件

监听文件可以配置在 config/swoole.php

 'listen'        => [
 				'connect' => 'app\listener\WsConnect',
 				'close' => 'app\listener\WsClose  ',
 				'test' => 'app\listener\test',
 				... //可监听更多自定义事件
        ],
                       

点击阅读全文

上一篇 2023年 5月 27日 am10:38
下一篇 2023年 5月 27日 am10:40