在 Laravel 中集成 Swoole 实现 WebSocket 服务器

本文介绍基于 LaravelS 扩展包将 Swoole 集成到 Laravel 项目实现 WebSocket 服务器的方法。包括创建 WebSocketService 类、修改配置文件、配置 Nginx 支持 WebSocket,最后演示了基于 Laravel 的 WebSocket 通信过程,后续还将实现广播通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上篇教程中,我们基于 Swoole 实现了简单的 WebSocket 服务器,然后在客户端通过 JavaScript 实现了 WebSocket 客户端,并演示了 WebSocket 的握手和通信过程,今天,学院君将基于 LaravelS 扩展包把 Swoole 集成到 Laravel 项目来实现 WebSocket 服务器,以便与客户端进行 WebSocket 通信从而实现广播功能。

创建 WebSocketService 类

关于 LaravelS 扩展包我们之前在介绍基于 Swoole 实现 HTTP 服务器的时候已经提到过了,这里不再赘述,没有安装的同学可以去参考那篇教程进行安装和配置,要基于该扩展包实现 WebSocket 服务器,首先首先需要创建一个实现了 Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface 接口的 WebSocketService 类:

 

 

1

<?php

2

3

namespace App\Services;

4

5

use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface;

6

use Illuminate\Support\Facades\Log;

7

use Swoole\Http\Request;

8

use Swoole\WebSocket\Frame;

9

use Swoole\WebSocket\Server;

10

11

class WebSocketService implements WebSocketHandlerInterface

12

{

13

    public function __construct()

14

    {

15

16

    }

17

18

    // 连接建立时触发

19

    public function onOpen(Server $server, Request $request)

20

    {

21

        // 在触发 WebSocket 连接建立事件之前,Laravel 应用初始化的生命周期已经结束,你可以在这里获取 Laravel 请求和会话数据

22

        // 调用 push 方法向客户端推送数据,fd 是客户端连接标识字段

23

        Log::info('WebSocket 连接建立');

24

        $server->push($request->fd, 'Welcome to WebSocket Server built on LaravelS');

25

    }

26

27

    // 收到消息时触发

28

    public function onMessage(Server $server, Frame $frame)

29

    {

30

        // 调用 push 方法向客户端推送数据

31

        $server->push($frame->fd, 'This is a message sent from WebSocket Server at ' . date('Y-m-d H:i:s'));

32

    }

33

34

    // 关闭连接时触发

35

    public function onClose(Server $server, $fd, $reactorId)

36

    {

37

        Log::info('WebSocket 连接关闭');

38

    }

39

}

在这个 WebSocket 服务器类中,需要实现接口中声明的方法,其实就是 WebSocket 通信事件的回调函数,和上篇教程介绍的原生实现基本一致,只是通过类进行了封装而已。

修改配置文件

接下来,打开配置文件 config/laravels.php,启用 WebSocket 通信并将刚刚创建的服务器类配置到对应的配置项:

 

 

1

'websocket' => [

2

    'enable' => true,

3

    'handler' => \App\Services\WebSocketService::class,

4

],

我们还可以在 swoole 配置项中配置 WebSocket 长连接的强制关闭逻辑:

 

 

1

'swoole' => [

2

    ...

3

 

4

    // 每隔 60s 检测一次所有连接,如果某个连接在 600s 内都没有发送任何数据,则关闭该连接

5

    'heartbeat_idle_time'      => 600,

6

    'heartbeat_check_interval' => 60,

7

 

8

    ...

9

],

配置 Nginx 支持 WebSocket

由于 WebSocket 通信是基于 HTTP 协议的,所以,我们还要配置 HTTP 服务器来支持 WebSocket 请求,以 Nginx 为例,我们在基于 Swoole 实现 HTTP 服务器一节中添加的 Nginx 配置文件基础上进行 WebSocket 配置,为了与之前基于 PHP-FPM 作为进程管理器的站点配置区分开,创建一个新的站点配置 todoapp-s.conf(基于待办任务项目进行测试),编辑配置文件内容如下:

 

 

1

map $http_upgrade $connection_upgrade {

2

    default upgrade;

3

    ''      close;

4

}

5

upstream laravels {

6

    # Connect IP:Port

7

    server workspace:5200 weight=5 max_fails=3 fail_timeout=30s;

8

    keepalive 16;

9

}

10

server {

11

    listen 80;

12

 

13

    server_name todo-s.test;

14

    root /var/www/todoapp/public;

15

 

16

    error_log /var/log/nginx/todoapp_s_error.log;

17

    access_log /var/log/nginx/todoapp_s_access.log;

18

 

19

    index index.php index.html index.htm;

20

 

21

    # Nginx handles the static resources(recommend enabling gzip), LaravelS handles the dynamic resource.

22

    location / {

23

        try_files $uri @laravels;

24

    }

25

 

26

    # Response 404 directly when request the PHP file, to avoid exposing public/*.php

27

    #location ~* \.php$ {

28

    #    return 404;

29

    #}

30

 

31

    # Http and WebSocket are concomitant, Nginx identifies them by "location"

32

    # !!! The location of WebSocket is "/ws"

33

    # Javascript: var ws = new WebSocket("ws://todo-s.test/ws");

34

    # 处理 WebSocket 通信

35

    location =/ws {

36

        # proxy_connect_timeout 60s;

37

        # proxy_send_timeout 60s;

38

        # proxy_read_timeout: Nginx will close the connection if the proxied server does not send data to Nginx in 60 seconds; At the same time, this close behavior is also affected by heartbeat setting of Swoole.

39

        # proxy_read_timeout 60s;

40

        proxy_http_version 1.1;

41

        proxy_set_header X-Real-IP $remote_addr;

42

        proxy_set_header X-Real-PORT $remote_port;

43

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

44

        proxy_set_header Host $http_host;

45

        proxy_set_header Scheme $scheme;

46

        proxy_set_header Server-Protocol $server_protocol;

47

        proxy_set_header Server-Name $server_name;

48

        proxy_set_header Server-Addr $server_addr;

49

        proxy_set_header Server-Port $server_port;

50

        proxy_set_header Upgrade $http_upgrade;

51

        proxy_set_header Connection $connection_upgrade;

52

        proxy_pass http://laravels;

53

    }

54

 

55

    location @laravels {

56

        # proxy_connect_timeout 60s;

57

        # proxy_send_timeout 60s;

58

        # proxy_read_timeout 60s;

59

        proxy_http_version 1.1;

60

        proxy_set_header Connection "";

61

        proxy_set_header X-Real-IP $remote_addr;

62

        proxy_set_header X-Real-PORT $remote_port;

63

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

64

        proxy_set_header Host $http_host;

65

        proxy_set_header Scheme $scheme;

66

        proxy_set_header Server-Protocol $server_protocol;

67

        proxy_set_header Server-Name $server_name;

68

        proxy_set_header Server-Addr $server_addr;

69

        proxy_set_header Server-Port $server_port;

70

        proxy_pass http://laravels;

71

    }

72

}

学院君的本地开发环境是 Laradock,所以配置的监听 IP 是 Docker 容器名称 workspace,如果你不是在 Laradock 中开发,需要将其改成自己的 Swoole WebSocket Server 监听 IP。

配置完成后,即可构建容器并重新启动:

 

 

1

docker-compose build nginx

2

docker-compose down

3

docker-compose up -d nginx mysql

此外,记得在对应 Laravel 项目根目录下 .env 环境配置文件中设置如下配置项:

 

 

1

LARAVELS_LISTEN_IP=workspace  // 这里的 IP 需要和 nginx upstream 中配置的监听 IP 保持一致

2

LARAVELS_DAEMONIZE=true

演示基于 Laravel 的 WebSocket 通信

在 Laravel 项目根目下启动 Swoole 服务器:

 

 

1

php bin/laravels start

启动成功后,就可以看到基于 Swoole 的 HTTP 服务器和 WebSocket 服务器信息了:

Laravel Swoole

然后,我们基于上一篇教程创建的 WebSocket 客户端,将其中的 WebSocket Server IP 和端口修改如下:

 

 

1

// 初始化 WebSocket 客户端套接字并建立与服务器的连接

2

var socket = new WebSocket("ws://todo-s.test/ws");

在浏览器中访问这个客户端 HTML 文件,在弹出窗口输入用户名:

然后点击「确定」,即可开始建立与 Laravel WebSocket 服务器的通信:

WebSocket 通信建立

在开发者工具栏 Network->WS 标签页同样可以看到基于 HTTP 协议的 Websocket 通信握手和建立过程:

WebSocket 通信握手

如果我们在输入框中发送消息,即可触发 WebSocket 服务器推送消息给客户端:

WebSocket 服务器推送消息到客户端

同时,在 storage/logs 目录下也可以看到通信连接建立与断开的日志信息:

 

 

1

[2019-05-22 13:55:02] local.INFO: WebSocket 连接建立  

2

[2019-05-22 13:55:10] local.INFO: WebSocket 连接关闭  

3

[2019-05-22 13:56:25] local.INFO: WebSocket 连接建立  

4

[2019-05-22 13:57:25] local.INFO: WebSocket 连接关闭  

5

[2019-05-22 14:01:18] local.INFO: WebSocket 连接建立  

6

[2019-05-22 14:02:20] local.INFO: WebSocket 连接关闭

在下一篇教程中,学院君将会把这个自定义的服务器作为 Laravel Echo 的服务端,在 Laravel 中实现基于 Swoole 的广播通信

 

https://laravelacademy.org/post/19700.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值