启用WebSocket服务器
WebSocket服务器监听的IP和端口与Http服务器相同。
1.创建WebSocket Handler类,并实现接口WebSocketHandlerInterface
。start时会自动实例化,不需要手动创建实例。
- namespace App\Services;
- use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface;
- use Swoole\Http\Request;
- use Swoole\WebSocket\Frame;
- use Swoole\WebSocket\Server;
- /**
- * @see https://wiki.swoole.com/wiki/page/400.html
- */
- class WebSocketService implements WebSocketHandlerInterface
- {
- // 声明没有参数的构造函数
- public function __construct()
- {
- }
- public function onOpen(Server $server, Request $request)
- {
- // 在触发onOpen事件之前Laravel的生命周期已经完结,所以Laravel的Request是可读的,Session是可读写的
- // \Log::info('New WebSocket connection', [$request->fd, request()->all(), session()->getId(), session('xxx'), session(['yyy' => time()])]);
- $server->push($request->fd, 'Welcome to LaravelS');
- // throw new \Exception('an exception');// 此时抛出的异常上层会忽略,并记录到Swoole日志,需要开发者try/catch捕获处理
- }
- public function onMessage(Server $server, Frame $frame)
- {
- // \Log::info('Received message', [$frame->fd, $frame->data, $frame->opcode, $frame->finish]);
- $server->push($frame->fd, date('Y-m-d H:i:s'));
- // throw new \Exception('an exception');// 此时抛出的异常上层会忽略,并记录到Swoole日志,需要开发者try/catch捕获处理
- }
- public function onClose(Server $server, $fd, $reactorId)
- {
- // throw new \Exception('an exception');// 此时抛出的异常上层会忽略,并记录到Swoole日志,需要开发者try/catch捕获处理
- }
- }
2.更改配置config/laravels.php
。
- // ...
- 'websocket' => [
- 'enable' => true, // 看清楚,这里是true
- 'handler' => \App\Services\WebSocketService::class,
- ],
- 'swoole' => [
- //...
- // dispatch_mode只能设置为2、4、5,https://wiki.swoole.com/wiki/page/277.html
- 'dispatch_mode' => 2,
- //...
- ],
- // ...
3.使用SwooleTable
绑定FD与UserId,可选的,Swoole Table示例。也可以用其他全局存储服务,例如Redis/Memcached/MySQL,但需要注意多个Swoole Server
实例时FD可能冲突。
4.与Nginx配合使用(推荐)
参考 WebSocket代理
- map $http_upgrade $connection_upgrade {
- default upgrade;
- '' close;
- }
- upstream laravels {
- # 通过 IP:Port 连接
- server 127.0.0.1:5200 weight=5 max_fails=3 fail_timeout=30s;
- # 通过 UnixSocket Stream 连接,小诀窍:将socket文件放在/dev/shm目录下,可获得更好的性能
- #server unix:/xxxpath/laravel-s-test/storage/laravels.sock weight=5 max_fails=3 fail_timeout=30s;
- #server 192.168.1.1:5200 weight=3 max_fails=3 fail_timeout=30s;
- #server 192.168.1.2:5200 backup;
- keepalive 16;
- }
- server {
- listen 80;
- # 别忘了绑Host哟
- server_name laravels.com;
- root /xxxpath/laravel-s-test/public;
- access_log /yyypath/log/nginx/$server_name.access.log main;
- autoindex off;
- index index.html index.htm;
- # Nginx处理静态资源(建议开启gzip),LaravelS处理动态资源。
- location / {
- try_files $uri @laravels;
- }
- # 当请求PHP文件时直接响应404,防止暴露public/*.php
- #location ~* \.php$ {
- # return 404;
- #}
- # Http和WebSocket共存,Nginx通过location区分
- # !!! WebSocket连接时路径为/ws
- # Javascript: var ws = new WebSocket("ws://laravels.com/ws");
- location =/ws {
- # proxy_connect_timeout 60s;
- # proxy_send_timeout 60s;
- # proxy_read_timeout:如果60秒内被代理的服务器没有响应数据给Nginx,那么Nginx会关闭当前连接;同时,Swoole的心跳设置也会影响连接的关闭
- # proxy_read_timeout 60s;
- proxy_http_version 1.1;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Real-PORT $remote_port;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header Host $http_host;
- proxy_set_header Scheme $scheme;
- proxy_set_header Server-Protocol $server_protocol;
- proxy_set_header Server-Name $server_name;
- proxy_set_header Server-Addr $server_addr;
- proxy_set_header Server-Port $server_port;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection $connection_upgrade;
- proxy_pass http://laravels;
- }
- location @laravels {
- # proxy_connect_timeout 60s;
- # proxy_send_timeout 60s;
- # proxy_read_timeout 60s;
- proxy_http_version 1.1;
- proxy_set_header Connection "";
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Real-PORT $remote_port;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header Host $http_host;
- proxy_set_header Scheme $scheme;
- proxy_set_header Server-Protocol $server_protocol;
- proxy_set_header Server-Name $server_name;
- proxy_set_header Server-Addr $server_addr;
- proxy_set_header Server-Port $server_port;
- proxy_pass http://laravels;
- }
- }
5.心跳配置
- Swoole的心跳配置
- // config/laravels.php
- 'swoole' => [
- //...
- // 表示每60秒遍历一次,一个连接如果600秒内未向服务器发送任何数据,此连接将被强制关闭
- 'heartbeat_idle_time' => 600,
- 'heartbeat_check_interval' => 60,
- //...
- ],
- Nginx读取代理服务器超时的配置
- # 如果60秒内被代理的服务器没有响应数据给Nginx,那么Nginx会关闭当前连接
- proxy_read_timeout 60s;