laravel接入websocket

1.1 laravels简介

Laravel-S 是快速集成 Swoole 到 Laravel 或 Lumen 之间开箱即用的适配器。Swoole 是 PHP 的一个扩展,可以通过 PHP 扩展的方式进行安装和启用。通过给laravel接入swoole,能够有效提高并发和性能。

1.2 laravels安装

环境要求:

安装指定版本

composer require "hhxsv5/laravel-s:~3.7.0" -vvv

1.3 注册Service Provider

laravel: 修改文件config/app.php

'providers' => [
    //...
    Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class,
],

Lumen: 修改文件bootstrap/app.php

$app->register(Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class);

1.4 laravels启动

bin/laravels {start|stop|restart|reload|info|help}

基本命令:

1.5 通过Supervisord监管主进程

[program:laravel-s-test]
directory=/var/wwww/laravel-s-test
command=/usr/local/bin/php bin/laravels start -i
numprocs=1
autostart=true
autorestart=true
startretries=3
user=www-data
redirect stderr=true
stdout_logfile=/var/log/supervisor/%(program_name)s.log

2 启用websocket服务

创建WebSocket Handler类,并实现接口WebSocketHandlerInterface。start时会自动实例化,不需要手动创建实例。

配置config/laravels.php

 'listen_ip'                => env('LARAVELS_LISTEN_IP', '0.0.0.0'),
    'listen_port'              => env('LARAVELS_LISTEN_PORT', 5209),
    'socket_type'              => defined('SWOOLE_SOCK_TCP') ? SWOOLE_SOCK_TCP : 1,
    'enable_coroutine_runtime' => false,
    'server'                   => env('LARAVELS_SERVER', 'LaravelS'),
    'handle_static'            => env('LARAVELS_HANDLE_STATIC', false),
    'laravel_base_path'        => env('LARAVEL_BASE_PATH', base_path()),
    'inotify_reload'           => [
        'enable'        => env('LARAVELS_INOTIFY_RELOAD', true),
        'watch_path'    => base_path(),
        'file_types'    => ['.php'],
        'excluded_dirs' => [],
        'log'           => true,
    ],
    'event_handlers'           => [],
    'websocket'                => [
        'enable' => true,
        'handler' => \App\Services\WebSocketService::class,
    ],

2.1 dispatch_mode 数据包分发策略

2.2 回调函数

  • onOpen:客户端连接websocket触发的回调函数
  • onMessage:客户端发送消息,即服务端接收消息触发的函数
  • onClose:客户端关闭websocket连接触发的函数

方法:

  • push:向客户端推送消息 $server->push($fd, $content);
  • disconnect 断开连接 ($server->disconnect($request->fd))
  • close:$server->close($request->fd);
  • isEstablished:检查是否有效的ws连接 $server->isEstablished($request->fd)
  • pack:打包消息
  • unpack:解析 WebSocket数据帧
  • 在应用中使用swoole实例:$swoole = app('swoole');

注:关于websocket业务逻辑处理在前三个回调函数之间进行

2.3 一些参数介绍

SwooleTable:用于WebSocket中一些参数绑定,如:UserId与FD绑定,推荐使用其它方式存储,如redis、memcache等缓存。 所有的Table实例均绑定在SwooleServer上,通过app('swoole')->xxxTable访问

   $this->wsTable->set('uid:' . $userId, ['value' => $request->fd]);// 绑定uid到fd的映射
   $this->wsTable->set('fd:' . $request->fd, ['value' => $userId]);// 绑定fd到uid的映射

心跳config设置

Nginx设置: proxy_read_timeout 60s 如果60秒内被代理的服务器没有响应数据给Nginx,那么Nginx会关闭当前连接

2.4 监听事件

系统事件:

可以在这些事件中重置或销毁一些全局或静态的变量,也可以修改当前的请求和响应。 laravels.received_request 将Swoole\Http\Request转成Illuminate\Http\Request后,在Laravel内核处理请求前。

laravels.generated_response 在Laravel内核处理完请求后,将Illuminate\Http\Response转成Swoole\Http\Response之前(下一步将响应给客户端)。

2.5 自定义异步事件task

异步事件依赖Swoole的AsyncTask,必须先设置config/laravels.php的swoole.task_worker_num。异步事件的处理能力受Task进程数影响,需合理设置task_worker_num。

通过new Task($initData)进行任务投递

创建监听器类

触发事件 delay(10):延迟10s触发 setTries(3):出现异常时,累计尝试3次

2.6 毫秒级任务定时器

基于Swoole的毫秒定时器,封装的定时任务,取代Linux的Crontab。 创建定时任务:

注册定时任务类

2.7 配置热更新

修改代码后reload几种策略 1.基于inotify,仅支持Linux 2.基于fswatch,支持OS X、Linux、Windows

在项目根目录下运行命令,监听当前目录

 ./bin/fswatch

监听app目录

./bin/fswatch ./app

3.基于inotifywait,仅支持Linux。 监听当前目录

./bin/inotify

监听app目录

./bin/inotify ./app

3 常见问题

3.1 单例问题

传统FPM下,单例模式的对象的生命周期仅在每次请求中,请求开始=>实例化单例=>请求结束后=>单例对象资源回收 Swoole Server下,所有单例对象会常驻于内存,这个时候单例对象的生命周期与FPM不同,请求开始=>实例化单例=>请求结束=>单例对象依旧保留,需要开发者自己维护单例的状态 如果项目中用到了Session、Authentication、JWT,需要用到cleaners清理器 清理器用于清理一些残留的全局变量、单例对象、静态属性,避免多次请求间数据污染。这些清理器类必须实现接口Hhxsv5\LaravelS\Illuminate\Cleaners\CleanerInterface。

3.2 常见的解决方案

1.通过XxxCleaner类来清理单例对象状态,此类需实现接口Hhxsv5\LaravelS\Illuminate\Cleaners\CleanerInterface,然后注册到laravels.php的cleaners中。 2.使用中间件来重置单例对象的状态。 3.如果是以ServiceProvider注册的单例对象,可添加该ServiceProvider到laravels.php的register_providers中,这样每次请求会重新注册该ServiceProvider,重新实例化单例对象

3.3 其它

1.需要通过Illuminate\Http\Request对象来获取请求信息,不能使用$_GET、$_POST、$_FILES、$_COOKIE、$_REQUEST、$_SESSION、$GLOBALS 等全局变量 2.推荐通过返回Illuminate\Http\Response对象来响应请求,不能使用函数像 dd()、exit()、die()、header()、setcookie()、http_response_code()。 3.各种单例的连接将被常驻内存,建议开启持久连接。 4.数据库连接,连接断开后会自动重连 5.声明的全局、静态变量必须手动清理或重置。 6.无限追加元素到静态或全局变量中,将导致内存爆满。

打 赏