启用WebSocket服务器

WebSocket服务器监听的IP和端口与Http服务器相同。

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

  1. namespace App\Services;
  2. use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface;
  3. use Swoole\Http\Request;
  4. use Swoole\WebSocket\Frame;
  5. use Swoole\WebSocket\Server;
  6. /**
  7. * @see https://wiki.swoole.com/wiki/page/400.html
  8. */
  9. class WebSocketService implements WebSocketHandlerInterface
  10. {
  11. // 声明没有参数的构造函数
  12. public function __construct()
  13. {
  14. }
  15. public function onOpen(Server $server, Request $request)
  16. {
  17. // 在触发onOpen事件之前Laravel的生命周期已经完结,所以Laravel的Request是可读的,Session是可读写的
  18. // \Log::info('New WebSocket connection', [$request->fd, request()->all(), session()->getId(), session('xxx'), session(['yyy' => time()])]);
  19. $server->push($request->fd, 'Welcome to LaravelS');
  20. // throw new \Exception('an exception');// 此时抛出的异常上层会忽略,并记录到Swoole日志,需要开发者try/catch捕获处理
  21. }
  22. public function onMessage(Server $server, Frame $frame)
  23. {
  24. // \Log::info('Received message', [$frame->fd, $frame->data, $frame->opcode, $frame->finish]);
  25. $server->push($frame->fd, date('Y-m-d H:i:s'));
  26. // throw new \Exception('an exception');// 此时抛出的异常上层会忽略,并记录到Swoole日志,需要开发者try/catch捕获处理
  27. }
  28. public function onClose(Server $server, $fd, $reactorId)
  29. {
  30. // throw new \Exception('an exception');// 此时抛出的异常上层会忽略,并记录到Swoole日志,需要开发者try/catch捕获处理
  31. }
  32. }

2.更改配置config/laravels.php

  1. // ...
  2. 'websocket' => [
  3. 'enable' => true, // 看清楚,这里是true
  4. 'handler' => \App\Services\WebSocketService::class,
  5. ],
  6. 'swoole' => [
  7. //...
  8. // dispatch_mode只能设置为2、4、5,https://wiki.swoole.com/wiki/page/277.html
  9. 'dispatch_mode' => 2,
  10. //...
  11. ],
  12. // ...

3.使用SwooleTable绑定FD与UserId,可选的,Swoole Table示例。也可以用其他全局存储服务,例如Redis/Memcached/MySQL,但需要注意多个Swoole Server实例时FD可能冲突。

4.与Nginx配合使用(推荐)

参考 WebSocket代理

  1. map $http_upgrade $connection_upgrade {
  2. default upgrade;
  3. '' close;
  4. }
  5. upstream laravels {
  6. # 通过 IP:Port 连接
  7. server 127.0.0.1:5200 weight=5 max_fails=3 fail_timeout=30s;
  8. # 通过 UnixSocket Stream 连接,小诀窍:将socket文件放在/dev/shm目录下,可获得更好的性能
  9. #server unix:/xxxpath/laravel-s-test/storage/laravels.sock weight=5 max_fails=3 fail_timeout=30s;
  10. #server 192.168.1.1:5200 weight=3 max_fails=3 fail_timeout=30s;
  11. #server 192.168.1.2:5200 backup;
  12. keepalive 16;
  13. }
  14. server {
  15. listen 80;
  16. # 别忘了绑Host哟
  17. server_name laravels.com;
  18. root /xxxpath/laravel-s-test/public;
  19. access_log /yyypath/log/nginx/$server_name.access.log main;
  20. autoindex off;
  21. index index.html index.htm;
  22. # Nginx处理静态资源(建议开启gzip),LaravelS处理动态资源。
  23. location / {
  24. try_files $uri @laravels;
  25. }
  26. # 当请求PHP文件时直接响应404,防止暴露public/*.php
  27. #location ~* \.php$ {
  28. # return 404;
  29. #}
  30. # Http和WebSocket共存,Nginx通过location区分
  31. # !!! WebSocket连接时路径为/ws
  32. # Javascript: var ws = new WebSocket("ws://laravels.com/ws");
  33. location =/ws {
  34. # proxy_connect_timeout 60s;
  35. # proxy_send_timeout 60s;
  36. # proxy_read_timeout:如果60秒内被代理的服务器没有响应数据给Nginx,那么Nginx会关闭当前连接;同时,Swoole的心跳设置也会影响连接的关闭
  37. # proxy_read_timeout 60s;
  38. proxy_http_version 1.1;
  39. proxy_set_header X-Real-IP $remote_addr;
  40. proxy_set_header X-Real-PORT $remote_port;
  41. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  42. proxy_set_header Host $http_host;
  43. proxy_set_header Scheme $scheme;
  44. proxy_set_header Server-Protocol $server_protocol;
  45. proxy_set_header Server-Name $server_name;
  46. proxy_set_header Server-Addr $server_addr;
  47. proxy_set_header Server-Port $server_port;
  48. proxy_set_header Upgrade $http_upgrade;
  49. proxy_set_header Connection $connection_upgrade;
  50. proxy_pass http://laravels;
  51. }
  52. location @laravels {
  53. # proxy_connect_timeout 60s;
  54. # proxy_send_timeout 60s;
  55. # proxy_read_timeout 60s;
  56. proxy_http_version 1.1;
  57. proxy_set_header Connection "";
  58. proxy_set_header X-Real-IP $remote_addr;
  59. proxy_set_header X-Real-PORT $remote_port;
  60. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  61. proxy_set_header Host $http_host;
  62. proxy_set_header Scheme $scheme;
  63. proxy_set_header Server-Protocol $server_protocol;
  64. proxy_set_header Server-Name $server_name;
  65. proxy_set_header Server-Addr $server_addr;
  66. proxy_set_header Server-Port $server_port;
  67. proxy_pass http://laravels;
  68. }
  69. }

5.心跳配置

  • Swoole的心跳配置
  1. // config/laravels.php
  2. 'swoole' => [
  3. //...
  4. // 表示每60秒遍历一次,一个连接如果600秒内未向服务器发送任何数据,此连接将被强制关闭
  5. 'heartbeat_idle_time' => 600,
  6. 'heartbeat_check_interval' => 60,
  7. //...
  8. ],
  • Nginx读取代理服务器超时的配置
  1. # 如果60秒内被代理的服务器没有响应数据给Nginx,那么Nginx会关闭当前连接
  2. proxy_read_timeout 60s;