欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Laravel 中使用 swoole 项目实战开发案例一 (建立 swoole 和前端通信)

程序员文章站 2023-10-31 11:09:46
1 开发需要环境 工欲善其事,必先利其器。在正式开发之前我们检查好需要安装的拓展,不要开发中发现这些问题,打断思路影响我们的开发效率。 安装 swoole 拓展包 安装 redis 拓展包 安装 laravel5.5 版本以上 如果你还不会用swoole就out了 2 Laravel 生成命令行 p ......

1 开发需要环境

工欲善其事,必先利其器。在正式开发之前我们检查好需要安装的拓展,不要开发中发现这些问题,打断思路影响我们的开发效率。

  • 安装 swoole 拓展包
  • 安装 redis 拓展包
  • 安装 laravel5.5 版本以上

如果你还不会用swoole就out了

 

2 laravel 生成命令行

  1. php artisan make:command swooledemo
class swooledemo extends command
{

protected $signature = 'swoole:demo';

protected $description = '这是关于swoole的一个测试demo';

public function __construct()
{
    parent::__construct();
}

public function handle()
{
    $this->line("hello world");
}
}

 

我们分别运行 php artisan 指令和 php artisan swoole:demo 会看到关于这个命令的说明,和输出 hello world。(laravel 命令行用法详解)

3 命令行逻辑代码

  • 编写一个最基础的 swoole 命令行逻辑代码
<?php

namespace app\console\commands;

use illuminate\console\command;
use illuminate\support\facades\redis;

class swooledemo extends command
{
    // 命令名称
    protected $signature = 'swoole:demo';
    // 命令说明
    protected $description = '这是关于swoole websocket的一个测试demo';
    // swoole websocket服务
    private static $server = null;

    public function __construct()
    {
        parent::__construct();
    }

    // 入口
    public function handle()
    {
        $this->redis = redis::connection('websocket');
        $server = self::getwebsocketserver();
        $server->on('open',[$this,'onopen']);
        $server->on('message', [$this, 'onmessage']);
        $server->on('close', [$this, 'onclose']);
        $server->on('request', [$this, 'onrequest']);
        $this->line("swoole服务启动成功 ...");
        $server->start();
    }

    // 获取服务
    public static function getwebsocketserver()
    {
        if (!(self::$server instanceof \swoole_websocket_server)) {
            self::setwebsocketserver();
        }
        return self::$server;
    }
    // 服务处始设置
    protected static  function setwebsocketserver():void
    {
        self::$server  = new \swoole_websocket_server("0.0.0.0", 9502);
        self::$server->set([
            'worker_num' => 1,
            'heartbeat_check_interval' => 60,    // 60秒检测一次
            'heartbeat_idle_time' => 121,        // 121秒没活动的
        ]);
    }

    // 打开swoole websocket服务回调代码
    public function onopen($server, $request)
    {
        if ($this->checkaccess($server, $request)) {\
            self::$server->push($request->fd,"打开swoole服务成功!");\
        }
    }
    // 给swoole websocket 发送消息回调代码
    public function onmessage($server, $frame)
    {

    }
    // http请求swoole websocket 回调代码
    public function onrequest($request,$response)
    {

    }
    // websocket 关闭回调代码
    public function onclose($serv,$fd)
    {
        $this->line("客户端 {$fd} 关闭");
    }
    // 校验客户端连接的合法性,无效的连接不允许连接
    public function checkaccess($server, $request):bool
    {
        $bres = true;
        if (!isset($request->get) || !isset($request->get['token'])) {
            self::$server->close($request->fd);
            $this->line("接口验证字段不全");
            $bres = false;
        } else if ($request->get['token'] !== "123456") {
            $this->line("接口验证错误");
            $bres = false;
        }
        return $bres;
    }
    // 启动websocket服务
    public function start()
    {
        self::$server->start();
    }

}

 

编写 websoket js 代码

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>swoole测试</title>
    <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
</head>
<body>
<h1>这是一个测试</h1>
</body>
<script>
    var ws;//websocket实例
    var lockreconnect = false;//避免重复连接
    var wsurl = 'ws://{{$_server["http_host"]}}:9502?page=home&token=123456';

    function initeventhandle() {
        ws.onclose = function () {
            reconnect(wsurl);
        };
        ws.onerror = function () {
            reconnect(wsurl);
        };
        ws.onopen = function () {
            //心跳检测重置
            heartcheck.reset().start();
        };
        ws.onmessage = function (event) {
            //如果获取到消息,心跳检测重置
            //拿到任何消息都说明当前连接是正常的
            var data = json.parse(event.data);
            heartcheck.reset().start();
        }
    }
    createwebsocket(wsurl);
    /**
     * 创建链接
     * @param url
     */
    function createwebsocket(url) {
        try {
            ws = new websocket(url);
            initeventhandle();
        } catch (e) {
            reconnect(url);
        }
    }
    function reconnect(url) {
        if(lockreconnect) return;
        lockreconnect = true;
        //没连接上会一直重连,设置延迟避免请求过多
        settimeout(function () {
            createwebsocket(url);
            lockreconnect = false;
        }, 2000);
    }
    //心跳检测
    var heartcheck = {
        timeout: 60000,//60秒
        timeoutobj: null,
        servertimeoutobj: null,
        reset: function(){
            cleartimeout(this.timeoutobj);
            cleartimeout(this.servertimeoutobj);
            return this;
        },
        start: function(){
            var self = this;
            this.timeoutobj = settimeout(function(){
                //这里发送一个心跳,后端收到后,返回一个心跳消息,
                //onmessage拿到返回的心跳就说明连接正常
                ws.send("heartbeat");
                self.servertimeoutobj = settimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了
                    ws.close();//如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
                }, self.timeout);
            }, this.timeout);
        },
        header:function(url) {
            window.location.href=url
        }

    }
</script>
</html>
访问前端页面 (显示如下说明前后端链接成功)

Laravel 中使用 swoole 项目实战开发案例一 (建立 swoole 和前端通信)