laravel整合workerman做聊天室
测试工具 http://www.blue-zero.com/WebSocket/
2018年8月6日17:28:24
<?php namespace App\Console\Commands; use Illuminate\Console\Command;
use Workerman\Worker;
use App\Work\ChatroomWork; class Chatroom extends Command { protected $taskserver;
/*
* 操作参数
* 注意只能在
* start 启动
* stop 停止
* relaod 只能重启逻辑代码,核心workerman_init无法重启,注意看官方文档
* status 查看状态
* connections 查看连接状态(需要Workerman版本>=3.5.0)
*
* 库 composer require workerman/workerman
*/
protected $action = array('start', 'stop', 'reload', 'status', 'connections'); /**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'Chatroom {action}'; /**
* The console command description.
*
* @var string
*/
protected $description = 'Chatroom'; /**
* 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;
}
//初始化workerman
ChatroomWork::workerman_init($action);
} }
<?php namespace App\Work; use App\Work\BaseWork as Base;
use Illuminate\Support\Facades\DB;
use App\Work\CommonWork;
use Workerman\Worker;
use Workerman\Lib\Timer;
use App\Models\OperationLog;
use App\Models\Users; class ChatroomWork extends Base { //全局的总连接数
static $connection_count = 0;
//单个房间最大的连接数
static $room_max_numbers;
//房间所有的用户连接数ID集合,判断发送给那些用户,绑定用户和connection_id
static $room_connection_array = []; public static function workerman_init($action = null) {
global $argv; $argv[0] = 'workerman:websocket';
$argv[1] = $action;
// $argv[2] = '-d';
// 心跳
define('HEARTBEAT_TIME', 30);
//初始化
$worker = new Worker("websocket://172.17.1.247:9090");
$worker->name = 'Chatroom';
//linux 用户线上是www
// $worker->user = 'www';
//守护模式信息输出文件地址
// $worker->stdoutFile = "./workerman.log";
//工作进程总数 测试环境4个
$worker->count = 4;
//正式环境
// $ws->count = 10;
//建立链接 处理逻辑
$worker->onConnect = function($connection) {
// 有新的客户端连接时,连接数+1
self::$connection_count++;
self::onConnect($connection);
};
//接受消息 处理逻辑
$worker->onMessage = function($connection, $data) { self::onMessage($connection, $data);
};
//关闭链接 处理逻辑
$worker->onClose = function($connection) {
// 客户端关闭时,连接数-1
self::$connection_count--;
self::onClose($connection);
}; // 进程启动后设置一个30秒运行一次的定时器
$worker->onWorkerStart = function($worker) {
// Timer::add(1, function()use($worker) {
// $time_now = time();
// foreach ($worker->connections as $connection) {
//
// }
// });
};
// 开始
Worker::runAll();
} //建立链接 处理逻辑
public static function onConnect($connection) {
//主动心跳ping测试60秒一次
// Timer::add(HEARTBEAT_TIME, function() use($connection) {
// $connection->send(json_encode(['code' => 200, 'msg' => '服务存活', 'data' => [], 'connections' => self::$connection_count]));
// });
} //接受消息 处理逻辑
public static function onMessage($connection, $data) {
//解析数据,非合法的json数据不处理 if (!empty($data)) {
if (is_json($data)) {
$data = json_decode($data, true); if ($data['action_type'] == 'ping') {
// 客户端回应服务端的心跳
$connection->send(json_encode(['code' => 200, 'msg' => '服务存活', 'data' => [], 'connections' => self::$connection_count]));
} elseif ($data['action_type'] == 'login') {
//用户登录
if ($data['is_login'] == 1) {
//匿名登录
self::$room_connection_array[$data['room_id']][$connection->id]['user_name'] = '匿名用户' . $connection->id; $connection->send(json_encode(['code' => 200, 'msg' => '匿名登录成功', 'data' => self::$room_connection_array, 'connections' => self::$connection_count]));
} elseif ($data['is_login'] == 2) {
//已登录
$Users = Users::where('id', $data['user_id'])->first();
if (empty($Users)) {
$connection->send(json_encode(['code' => 201, 'msg' => '用户ID无效或者错误', 'data' => [], 'connections' => self::$connection_count]));
} else {
$Users = $Users->toArray();
self::$room_connection_array[$data['room_id']][$connection->id]['user_name'] = empty($Users['realname']) ? $data['user_id'] : $Users['realname']; $connection->send(json_encode(['code' => 200, 'msg' => '登录成功', 'data' => self::$room_connection_array, 'connections' => self::$connection_count]));
}
} else {
$connection->send(json_encode(['code' => 201, 'msg' => '登录类型数据错误', 'data' => [], 'connections' => self::$connection_count]));
}
} elseif ($data['action_type'] == 'broadcast_to_all') {
//只发给房间的所有的人,除去自己
foreach ($connection->worker->connections as $con) {
foreach (self::$room_connection_array[$data['room_id']] as $k => $v) {
// p($con->id);
// p($k);
if ($k == $con->id && $con->id != $connection->id) {
$con->send($data['message']);
}
}
}
} elseif ($data['action_type'] == 'broadcast_to_one') { } else {
$connection->send(json_encode(['code' => 201, 'msg' => 'action_type类型错误', 'data' => [], 'connections' => self::$connection_count]));
}
}
} else {
$connection->send(json_encode(['code' => 201, 'msg' => '数据请求为空', 'data' => [], 'connections' => self::$connection_count]));
}
} //关闭链接 处理逻辑
public static function onClose($connection) {
//检索$connection->id 是否有在self::$room_connection_array中,有的话就剔除 foreach (self::$room_connection_array as $k => $v) {
foreach ($v as $kk => $vv) {
if ($kk == $connection->id) {
unset(self::$room_connection_array[$k][$connection->id]);
}
}
}
// p(self::$room_connection_array['100']);
} }
{"action_type":"login","is_login":1,"room_id":101} //登录 {"action_type":"broadcast_to_all","room_id":100,"message":"111"} //发送消息 为什么不用switch代码会看起来更清晰,因为有bug,对字符串匹配的不好
注意:
1,$connection就是当前的连接数据
2,因为未根据work id做房间划分,不知道在超出单个work连接时候会不会出问题
3,可以根据实际压力去划分一个work的最大连接数,这里是简单的测试demo所以未做具体的细节划分
4,这里应该结合session来做处理数据,但是我只是根据发送数据来区别用户,你可以在登录的发送数据的时候根据session处理数据,看需要,必须要返回用户列表,就直接把room id下面的所有用户名返回就OK
5,workerman用起来其实还是比较简单的,但是我这种结合laravel的整合是有问题,比如现在我有一个消息推送,一个聊天室就没办法放在一起使用,必须用别的办法,如果是单功能就比较容易,直接结合,我有一个骚办法就是直接
复制artisan入口文件,直接增加新入口artisan1,经过测试完全没有问题,但是其实不是很好的解决方案,如果要用就先这么上吧 如果你觉得麻烦可以是gateway做比较简单
2019年7月12日09:43:56
注意:上面是临时测试代码。业务代码使用try catch处理异常和错误
laravel整合workerman做聊天室的更多相关文章
- laravel整合workerman做消息推送系统
官方建议分离 workerman和mvc框架的结合,我去,这不是有点脑缺氧吗? 大量的业务逻辑,去独立增加方法和类库在写一次,实际业务中是不现实和不实际的 gateway增加一些这方面的工作,但是我看 ...
- Spring Boot2 系列教程 (十七) | 整合 WebSocket 实现聊天室
微信公众号:一个优秀的废人.如有问题,请后台留言,反正我也不会听. 前言 昨天那篇介绍了 WebSocket 实现广播,也即服务器端有消息时,将消息发送给所有连接了当前 endpoint 的浏览器.但 ...
- Workerman创建聊天室实例
// 标记是全局启动 define('GLOBAL_START', 1); require_once __DIR__ . '/Workerman/Connection.php'; require_on ...
- workerman搭建聊天室
首先,先打开官网手册 http://doc.workerman.net/ 根据手册里安装里的提示,完成环境检测,和安装对应的扩展,并把对应的WorkerMan代码包下载解压至根目录 在根目录下创建 ...
- 使用nodejs引用socket.io做聊天室
Server: var app = require('http').createServer(handler) , io = require('socket.io').listen(app) , fs ...
- 百行go代码构建p2p聊天室
百行go代码构建p2p聊天室 百行go代码构建p2p聊天室 1. 上手使用 2. whisper 原理 3. 源码解读 3.1 参数说明 3.1 连接主节点 3.2 我的标识 3.2 配置我的节点 3 ...
- 以太坊系列之十八: 百行go代码构建p2p聊天室
百行go代码构建p2p聊天室 百行go代码构建p2p聊天室 1. 上手使用 2. whisper 原理 3. 源码解读 3.1 参数说明 3.1 连接主节点 3.2 我的标识 3.2 配置我的节点 3 ...
- 对接融云即时通讯组件SDK,轻松实现App聊天室
我好像特别喜欢做聊天室类的东东,刚折腾完微软的SignalR又折腾App.本来想研究研究XMPP的,由于服务器的搭建问题,先采用一个第三方的吧,看看效果如何.听到弟弟说他们公司用到了融云,我也下载个S ...
- 使用原生node写一个聊天室
在学习node的时候都会练习做一个聊天室的项目,主要使用socket.io模块和http模块.这里我们使用更加原始的方式去写一个在命令行聊天的聊天室. http模块,socket.io都是高度封装之后 ...
随机推荐
- MySQL学习3 - 数据表的操作
本节掌握 一.存储引擎(了解) 二.mysql支持的存储引擎 1.InnoDB 存储引擎 2.MyISAM 存储引擎 3.NDB 存储引擎 4.Memory 存储引擎 5.Infobright 存储引 ...
- Vue技术内幕 出去看看吧 实例化+挂载
实例化时挂载DOM 从 Vue.prototype.$mount 挂载函数开始 有 template配置项时生成 render函数
- Saltstack自动化操作记录(2)-配置使用
之前梳理了Saltstack自动化操作记录(1)-环境部署,下面说说saltstack配置及模块使用: 为了试验效果,再追加一台被控制端minion机器192.168.1.118需要在master控制 ...
- MS SQL Server 时间函数
日期和时间数据类型 数据类型 存储(字节) 日期范围 精确度 格式示例 DateTime 8 1753年1月1日 - 9999年12月31日 3 1/3毫秒 yyyy-MM-dd hh:mm:ss.n ...
- php 新闻上一条下一条
public function prevnext($table,$id,$where=[]){ $ids=db($table)->field('id,title')->order('sor ...
- H5新特性之data-*
简单介绍:html5的data-*能够为标签添加一些自定义的属性和值,并且这种自定义的属性和值可以通过js来获取,十分的便捷 代码: //html<tr th:each="plan : ...
- PHP源码安装后设置别名
PHP源码安装后测试是否能正常运行 每次在php目录./bin./php调用php很不方便,可以设置别名(方法一) vi ~/.bash_profile (修改根目录下这个文件) 设置完成后还 ...
- 手动部署 kubernetes HA 集群
前言 关于kubernetes HA集群部署的方式有很多种(这里的HA指的是master apiserver的高可用),比如通过keepalived vip漂移的方式.haproxy/nginx负载均 ...
- 002.RHCS-配置Ceph存储集群
一 前期准备 [kiosk@foundation0 ~]$ ssh ceph@serverc #登录Ceph集群节点 [ceph@serverc ~]$ ceph health #确保集群状态正常 H ...
- 原生JavaScript中动画与特效的实现原理
现如今,许多页面上均有一些动画效果.适当的动画效果可以在一定程度上提高页面的美观度,具有提示效果的动画可以增强页面的易用性. 实现页面动画的途径一般有两种. 一种是通过操作JavaScript间接操作 ...