基于 Swoole 构建高性能 Laravel 应用系列 —— 在 Laravel 中集成 Swoole 实现 WebSocket 服务器

栏目: PHP · 发布时间: 5年前

内容简介:在上篇教程中,我们基于 Swoole 实现了简单的 WebSocket 服务器,然后在客户端通过 JavaScript 实现了 WebSocket 客户端,并演示了 WebSocket 的握手和通信过程,今天,学院君将基于关于 LaravelS 扩展包我们之前在介绍在这个 WebSocket 服务器类中,需要实现接口中声明的方法,其实就是 WebSocket 通信事件的回调函数,和

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

创建 WebSocketService 类

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

<?php

namespace App\Services;

use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface;
use Illuminate\Support\Facades\Log;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;

class WebSocketService implements WebSocketHandlerInterface
{
    public function __construct()
    {

    }

    // 连接建立时触发
    public function onOpen(Server $server, Request $request)
    {
        // 在触发 WebSocket 连接建立事件之前,Laravel 应用初始化的生命周期已经结束,你可以在这里获取 Laravel 请求和会话数据
        // 调用 push 方法向客户端推送数据,fd 是客户端连接标识字段
        Log::info('WebSocket 连接建立');
        $server->push($request->fd, 'Welcome to WebSocket Server built on LaravelS');
    }

    // 收到消息时触发
    public function onMessage(Server $server, Frame $frame)
    {
        // 调用 push 方法向客户端推送数据
        $server->push($frame->fd, 'This is a message sent from WebSocket Server at ' . date('Y-m-d H:i:s'));
    }

    // 关闭连接时触发
    public function onClose(Server $server, $fd, $reactorId)
    {
        Log::info('WebSocket 连接关闭');
    }
}

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

修改配置文件

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

'websocket' => [
    'enable' => true,
    'handler' => \App\Services\WebSocketService::class,
],

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

'swoole' => [
    ...

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

    ...
],

配置 Nginx 支持 WebSocket

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

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
upstream laravels {
    # Connect IP:Port
    server workspace:5200 weight=5 max_fails=3 fail_timeout=30s;
    keepalive 16;
}
server {
    listen 80;

    server_name todo-s.test;
    root /var/www/todoapp/public;

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

    index index.php index.html index.htm;

    # Nginx handles the static resources(recommend enabling gzip), LaravelS handles the dynamic resource.
    location / {
        try_files $uri @laravels;
    }

    # Response 404 directly when request the PHP file, to avoid exposing public/*.php
    #location ~* \.php$ {
    #    return 404;
    #}

    # Http and WebSocket are concomitant, Nginx identifies them by "location"
    # !!! The location of WebSocket is "/ws"
    # Javascript: var ws = new WebSocket("ws://todo-s.test/ws");
    # 处理 WebSocket 通信
    location =/ws {
        # proxy_connect_timeout 60s;
        # proxy_send_timeout 60s;
        # 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.
        # 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;
    }
}

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

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

docker-compose build nginx
docker-compose down
docker-compose up -d nginx mysql

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

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

演示基于 Laravel 的 WebSocket 通信

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

php bin/laravels start

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

基于 Swoole 构建高性能 Laravel 应用系列 —— 在 Laravel 中集成 Swoole 实现 WebSocket 服务器

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

// 初始化 WebSocket 客户端套接字并建立与服务器的连接
var socket = new WebSocket("ws://todo-s.test/ws");

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

基于 Swoole 构建高性能 Laravel 应用系列 —— 在 Laravel 中集成 Swoole 实现 WebSocket 服务器

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

基于 Swoole 构建高性能 Laravel 应用系列 —— 在 Laravel 中集成 Swoole 实现 WebSocket 服务器

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

基于 Swoole 构建高性能 Laravel 应用系列 —— 在 Laravel 中集成 Swoole 实现 WebSocket 服务器

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

基于 Swoole 构建高性能 Laravel 应用系列 —— 在 Laravel 中集成 Swoole 实现 WebSocket 服务器

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

[2019-05-22 13:55:02] local.INFO: WebSocket 连接建立  
[2019-05-22 13:55:10] local.INFO: WebSocket 连接关闭  
[2019-05-22 13:56:25] local.INFO: WebSocket 连接建立  
[2019-05-22 13:57:25] local.INFO: WebSocket 连接关闭  
[2019-05-22 14:01:18] local.INFO: WebSocket 连接建立  
[2019-05-22 14:02:20] local.INFO: WebSocket 连接关闭

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


以上所述就是小编给大家介绍的《基于 Swoole 构建高性能 Laravel 应用系列 —— 在 Laravel 中集成 Swoole 实现 WebSocket 服务器》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

可伸缩架构

可伸缩架构

【美】Lee Atchison / 张若飞、张现双 / 电子工业出版社 / 2017-7 / 65

随着互联网的发展越来越成熟,流量和数据量飞速增长,许多公司的关键应用程序都面临着伸缩性的问题,系统变得越来越复杂和脆弱,从而导致风险上升、可用性降低。《可伸缩架构:面向增长应用的高可用》是一本实践指南,让IT、DevOps和系统稳定性管理员能够了解到,如何避免应用程序在发展过程中变得缓慢、数据不一致或者彻底不可用等问题。规模增长并不只意味着处理更多的用户,还包括管理更多的风险和保证系统的可用性。作......一起来看看 《可伸缩架构》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具

html转js在线工具
html转js在线工具

html转js在线工具