laravel-s实现高性能webSocket服务

Posted willem_chen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了laravel-s实现高性能webSocket服务相关的知识,希望对你有一定的参考价值。

1 安装

首先php需要安装swoole扩展,仅支持 Linux、FreeBSD、MacOS 三种操作系统。
安装 laravel,安装 LaravelS 扩展包。

[root@bogon laravels]# php -m
[PHP Modules]
swoole

在这里插入图片描述
参考文献
在这里插入图片描述

基于 LaravelS 构建 HTTP 服务器

nginx 为例,进行示例演示。

配置 Nginx

我们知道在使用 Nginx 作为 Web 服务器的时候,前端资源文件,比如 CSS、JS、图片等静态资源都是通过 Nginx 进行处理的,比较高效,而 PHP 脚本请求这种动态资源都是转发到后端 PHP-FPM 进程进行处理,如果要基于 Swoole 实现高性能 HTTP 服务器,则这个 HTTP 服务器替代的也是 PHP-FPM 的职能,也就是说,我们将原本转发到 PHP-FPM 进程的请求转发给 Swoole 进行处理。在本例中,就是转发给 LaravelS 服务。

配置文件

upstream laravels {
    # Connect IP:Port
    server 172.20.31.97:5200 weight=5 max_fails=3 fail_timeout=30s;
    keepalive 16;
}
server {
    listen 80;
    
    server_name www.thhir.com;
    root /www/wwwroot/laravels/public;
    index index.php index.html index.htm;
    
    # Nginx 处理静态资源,LaravelS 处理动态资源
    location / {
        try_files $uri @laravels;
    }
    
    location @laravels {
        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;
    }
}

配置 Laravel 应用
接下来,在 blog 项目根目录下打开 .env,新增下面两条配置:

LARAVELS_LISTEN_IP=172.20.31.97
LARAVELS_DAEMONIZE=true

LARAVELS_LISTEN_IP 用于设置 LaravelS 监听的 IP 地址,这里的地址和 Nginx 配置转发的 IP 地址保持一致,就是 workspace 容器名,LARAVELS_DAEMONIZE 用于设置后台启动 LaravelS 服务。

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

LaravelS 扩展包把 Swoole 集成到 Laravel 项目来实现 WebSocket 服务器,以便与客户端进行 WebSocket 通信从而实现广播功能。

1 修改配置文件

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

'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,
    //...
],

2 创建 WebSocketService 类

在app文件夹下新建Services文件夹,新建WebSocketService.php文件

<?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, '欢迎使用基于LaravelS的WebSocket服务器');
    }

    // 收到消息时触发
    public function onMessage(Server $server, Frame $frame)
    {
        // 调用 push 方法向客户端推送数据
        // $server->push($frame->fd, '这是从WebSocket服务器发送的消息 ' . date('Y-m-d H:i:s'));
        
        $server->push($frame->fd, "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\\n");
    }

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

3 测试

新建一个控制器和视图和路由

Route::get('text', 'TextController@text');
<?php

namespace App\\Http\\Controllers;

use App\\Exceptions\\ApiException;
use App\\GoodsCategory;
use Common;
use Illuminate\\Http\\Request;

class TextController extends Controller
{
    public function text()
    {
    	return view('index');
    }
}

view视图

<!DOCTYPE html>
<html>
<head>
   <meta charset="UTF-8">
   <title>Chat Client</title>
</head>
<body>
<script>
   window.onload = function () {
       var nick = prompt("Enter your nickname");
       var input = document.getElementById("input");
       input.focus();

       // 初始化客户端套接字并建立连接
       var socket = new WebSocket("ws://www.thhir.com:5200");
       
       // 连接建立时触发
       socket.onopen = function (event) {
           console.log("webSocket 链接成功"); 
       }

       // 接收到服务端推送时执行
       socket.onmessage = function (event) {
           var msg = event.data;
           var node = document.createTextNode(msg);
           var div = document.createElement("div");
           div.appendChild(node);
           document.body.insertBefore(div, input);
           input.scrollIntoView();
       };
       
       // 连接关闭时触发
       socket.onclose = function (event) {
           console.log("WebSocket 关闭连接"); 
       }

       input.onchange = function () {
           var msg = nick + ": " + input.value;
           // 将输入框变更信息通过 send 方法发送到服务器
           socket.send(msg);
           input.value = "";
       };
   }
</script>
<input id="input" style="width: 100%;">
</body>
</html>

预览效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

以上是关于laravel-s实现高性能webSocket服务的主要内容,如果未能解决你的问题,请参考以下文章

如何使用hhxsv5/laravel-s的异步任务队列

Java实现高性能WebSocket即时消息服务

怎么使用 Socket.io 连接 WebSocket 服务

node.js搭建简单服务器,用于前端测试websocket链接方法和性能测试

100,000 个并发连接的 WebSocket 服务器是啥?

一文读懂jmeter的websocket接口性能测试