测试工具  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做聊天室的更多相关文章

  1. laravel整合workerman做消息推送系统

    官方建议分离 workerman和mvc框架的结合,我去,这不是有点脑缺氧吗? 大量的业务逻辑,去独立增加方法和类库在写一次,实际业务中是不现实和不实际的 gateway增加一些这方面的工作,但是我看 ...

  2. Spring Boot2 系列教程 (十七) | 整合 WebSocket 实现聊天室

    微信公众号:一个优秀的废人.如有问题,请后台留言,反正我也不会听. 前言 昨天那篇介绍了 WebSocket 实现广播,也即服务器端有消息时,将消息发送给所有连接了当前 endpoint 的浏览器.但 ...

  3. Workerman创建聊天室实例

    // 标记是全局启动 define('GLOBAL_START', 1); require_once __DIR__ . '/Workerman/Connection.php'; require_on ...

  4. workerman搭建聊天室

    首先,先打开官网手册   http://doc.workerman.net/ 根据手册里安装里的提示,完成环境检测,和安装对应的扩展,并把对应的WorkerMan代码包下载解压至根目录 在根目录下创建 ...

  5. 使用nodejs引用socket.io做聊天室

    Server: var app = require('http').createServer(handler) , io = require('socket.io').listen(app) , fs ...

  6. 百行go代码构建p2p聊天室

    百行go代码构建p2p聊天室 百行go代码构建p2p聊天室 1. 上手使用 2. whisper 原理 3. 源码解读 3.1 参数说明 3.1 连接主节点 3.2 我的标识 3.2 配置我的节点 3 ...

  7. 以太坊系列之十八: 百行go代码构建p2p聊天室

    百行go代码构建p2p聊天室 百行go代码构建p2p聊天室 1. 上手使用 2. whisper 原理 3. 源码解读 3.1 参数说明 3.1 连接主节点 3.2 我的标识 3.2 配置我的节点 3 ...

  8. 对接融云即时通讯组件SDK,轻松实现App聊天室

    我好像特别喜欢做聊天室类的东东,刚折腾完微软的SignalR又折腾App.本来想研究研究XMPP的,由于服务器的搭建问题,先采用一个第三方的吧,看看效果如何.听到弟弟说他们公司用到了融云,我也下载个S ...

  9. 使用原生node写一个聊天室

    在学习node的时候都会练习做一个聊天室的项目,主要使用socket.io模块和http模块.这里我们使用更加原始的方式去写一个在命令行聊天的聊天室. http模块,socket.io都是高度封装之后 ...

随机推荐

  1. Element老司机开车了

    orm Select选择器   坑: 1.选择器视图层一直渲染最后一个元素(value-key作为唯一标识符是关键)2.视图不更新,没有在data函数中声明变量,或者其他地方重置了已经声明过得变量 o ...

  2. JAVA进阶7

    间歇性混吃等死,持续性踌躇满志系列-------------第7天 1.Map接口的常用方法 import java.util.HashMap; import java.util.Map; publi ...

  3. web.xml配置文件中的async-supportedtrueasync-supported

    web.xml标题头替换为: <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" ...

  4. 第六章 使用 Bootstrap Typeahead 组件(百度下拉效果)(续)

    官方:http://twitter.github.io/typeahead.js/ 示例:http://twitter.github.io/typeahead.js/examples/(本文展示:Op ...

  5. css杂项补充

    css杂项补充 一.块与内联 1.块 独行显示 支持宽高,宽度默认适应父级,高度默认由子级或内容撑开 设置宽高后,采用设置的宽高 2.内联 同行显示 不支持宽高 margin上下无效果,左右会起作用, ...

  6. 洛谷P3343 [ZJOI2015]地震后的幻想乡 [DP,概率期望]

    传送门 思路 题目给了一个提示:对于\(n\)个\([0,1]\)的随机变量,其中第\(k\)小的期望大小是\(\frac{k}{n+1}\). 这引导我们枚举边的相对大小的全排列,然后求最小生成树 ...

  7. ios 给微信开发一个插件并安装到未越狱的手机上教程

    现来整体说一下思路,首先给越狱的手机开发一个插件并安装上去,然后去越狱手机上找到相应的动态库和对应的微信APP安装包,拷贝出来,然后重新签名,就可以安装到未越狱的手机上了 1.首先你的电脑需要安装th ...

  8. redis数据备份与恢复

    1.启动redis 进入redis目录 redis-cli 2.数据备份 redis 127.0.0.1:6379> SAVE 该命令将在 redis 备份目录中创建dump.rdb文件. 3. ...

  9. python的位置参数、默认参数、关键字参数、可变参数区别

    一.位置参数 调用函数时根据函数定义的参数位置来传递参数. #!/usr/bin/env python # coding=utf-8 def print_hello(name, sex): sex_d ...

  10. 全文搜索引擎Elasticsearch入门实践

    全文搜索引擎Elasticsearch入门实践 感谢阮一峰的网络日志全文搜索引擎 Elasticsearch 入门教程 安装 首先需要依赖Java环境.Elasticsearch官网https://w ...