laravel-admin集成workerman实现websocket长链接
·
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
更多推荐


所有评论(0)