1. 安装workerman
composer require workerman/workerman -vvv

注: -vvv是查看composer加载详情的意思

2.创建laravel自定义命令
php artisan make:command Workerman

注:执行这段命令后会在\app\Console\Commands文件夹下生成Workerman.php文件

3.Workerman.php文件代码 :

<?php
 
namespace App\Console\Commands;
 
use App\Http\Workerman\WorkermanUdp; //这个文件内容基本与WorkermanWeb相同,用于同时启用2个workerman服务,可忽略
use App\Http\Workerman\WorkermanWeb;
use Illuminate\Console\Command;
use Workerman\Worker;
 
class Workerman extends Command
{
    protected $action = array('start','daemon', 'stop', 'reload', 'status', 'connections');
 
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'workerman {action}';
 
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Start a Workerman:websocket server.';
 
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }
 
    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $action = $this->argument('action');
        if (!in_array($action, $this->action)) {
            $this->error('Error Action');
            exit;
        }
        WorkermanWeb::workerman_init($action);
 
        //如果需要同时启动两个workerman服务 则把文件中的头尾提出来,如不需要可忽略.
        //重写cli模式下的参数
        //global $argv;
        //$argv[0] = 'workerman';
        //$argv[1] = $action;
        //if ($action == 'daemon') {
          //  $argv[1] = 'start';
          //  $argv[2] = '-d';
        //}
        //define('HEARTBEAT_TIME', 30);//心跳
 
        //WorkermanWeb::workerman_init($action);
        //WorkermanUdp::workerman_init($action);
        
        //Worker::runAll();
 
    }
}

在这个文件中引入了一个执行文件App\Http\Workerman\WorkermanWeb (路径可不同);

4.WorkermanWeb.php文件代码:

<?php
/**
 * Notes:
 * Author:李逍遥 xiadonghu@imaodu.com
 * Date: 2020/9/2
 * Time: 10:14
 */
 
namespace App\Http\Workerman;
 
 
use Workerman\Lib\Timer;
use Workerman\Worker;
 
class WorkermanWeb
{
    public static function workerman_init($action = null)
    {
        global $argv;
        $argv[0] = 'workerman:websocket'; //无所谓写什么,凑数的
        $argv[1] = $action;
        if ($action == 'daemon') {
            $argv[1] = 'start';
            $argv[2] = '-d';
        }
        //心跳
        define('HEARTBEAT_TIME', 30);
        //初始化
        $worker = new Worker("websocket://0.0.0.0:1236");
        $worker->name = 'Infusion Alarm';
        //linux 用户线上是www
        //$worker->user = 'www';
        //守护模式信息输出文件地址
        //$worker->stdoutFile = "./workerman.log";
        //工作进程总数 测试环境4个
        $worker->count = 4;
        //正式环境
        //$ws->count = 10;
        //建立链接 处理逻辑
        $worker->onConnect = function ($connection) {
            self::onConnect($connection);
        };
        //接受消息 处理逻辑
        $worker->onMessage = function ($connection, $data) {
            self::onMessage($connection, $data);
        };
        //关闭链接 处理逻辑
        $worker->onClose = function ($connection) {
            self::onClose($connection);
        };
        // 进程启动后设置一个30秒运行一次的定时器
        $worker->onWorkerStart = function ($worker) {
            Timer::add(30, function () use ($worker) {
                $time_now = time();
                foreach($worker->connections as $connection) {
                    // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
                    if (empty($connection->lastMessageTime)) {
                        $connection->lastMessageTime = $time_now;
                        continue;
                    }
                    // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
                    if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
                        $connection->close();
                    }
                }
            });
        };
        // 开始
        Worker::runAll();
    }
 
    //建立链接 处理逻辑
    public static function onConnect($connection)
    {
        $connection->send(json_encode([
            'code' => 20001,
            'massage' => '请求成功',
            'data' => [],
        ]));
 
 
        //测试5秒一次 线上30秒一次
        //Timer::add(10, function () use ($connection) {
 
        //});
    }
 
    //接受消息 处理逻辑
    public static function onMessage($connection, $data)
    {
        // 给connection临时设置一个lastMessageTime属性,用来记录上次收到消息的时间
        $connection->lastMessageTime = time();
        //解析数据
        if (!empty($data)) {
                $data = json_decode($data, true);
                switch ($data['type']) {
                    // 客户端回应服务端的心跳
                    case 'ping':
                        $connection->send(json_encode([
                            'code' => 30000,
                            'massage' => '服务存活',
                            'data' => [],
                        ]));
                        break;
                    case 'alarm_list':
                        //在这里可以处理业务逻辑
                        $connection->send(json_encode([
                            'code' => 20000,
                            'massage' => '获取报警列表成功',
                            'data' => [],
                        ]));
                        break;
                    default:
                        break;
                }
        } else {
            $connection->send(json_encode([
                'code' => 201,
                'massage' => '数据请求为空',
                'data' => [],
            ]));
        }
    }
 
    //关闭链接 处理逻辑
    public static function onClose($connection)
    {
 
    }
}

5.启动workerman

php artisan workerman start  //开启 
php artisan workerman daemon //后台开启
php artisan workerman stop //关闭
php artisan workerman status //状态

开启后执行status的截图:
在这里插入图片描述

6.客户端(js)代码:

 var haha = {'type': 'alarm_list', 'department_id': 1};
 
    var send = JSON.stringify(haha);
 
    ws = new WebSocket("ws://127.0.0.1:1236");
 
    ws.onopen = function () {
        console.log("连接成功");
        setInterval(function () {
            ws.send(send);
        }, 1000)
    };
 
    ws.onmessage = function (e) {
        console.log("收到服务端的消息:" + e.data);
    };

js代码在console中执行的截图:
在这里插入图片描述

在这里插入图片描述

 我一般是用onMessage函数来处理业务逻辑的,也就是说前端需要开一个定时器访问websocket来处理长链接数据.不知这种方式是否合理,望大佬们指正.

这篇文章参考自https://www.cnblogs.com/zx-admin/p/9419679.html
————————————————
版权声明:本文为CSDN博主「恶魔楚轩」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_37619318/article/details/108363782

更多推荐