怎么用swoole + js + redis实现简易聊天室
发表于:2025-02-03 作者:千家信息网编辑
千家信息网最后更新 2025年02月03日,这篇文章主要介绍"怎么用swoole + js + redis实现简易聊天室",在日常操作中,相信很多人在怎么用swoole + js + redis实现简易聊天室问题上存在疑惑,小编查阅了各式资料,
千家信息网最后更新 2025年02月03日怎么用swoole + js + redis实现简易聊天室
这篇文章主要介绍"怎么用swoole + js + redis实现简易聊天室",在日常操作中,相信很多人在怎么用swoole + js + redis实现简易聊天室问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"怎么用swoole + js + redis实现简易聊天室"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
公司需要用到在线聊天功能,先写了个demo出来展示效果。
主要用到了swoole的websocket,task和redis的string,hash,set,zet等。
聊天室分为10个频道,可以切换频道,频道计数等。
目前还没做聊天内容的加密。
按需求,聊天内容可能会每个频道保留最近一百条,聊天加密的话考虑aes,也有可能不加。后续看情况了。
目前还没做异常处理。回头继续完善之后可能会再进行更新。
先上代码吧,有疑问可以留言交流。这里是html代码 可以自己引入jq地址。
WebSocketTestPage
服务端代码
['uid','gid'], 1 => ['new_room','old_room'], 2 => ['level','data','room_id','uid','name','head'], 4 => ['level','data','gid','uid','name','head'], ]; public function __construct() { if(!isset($this->redis)){ $this->redis = $this->_getRedis(); $this->redis->select(10); $this->redis->flushDB(); } $this->_resetChatNum(); if(!isset($this->ws)){ $this->ws = new swoole_websocket_server( HOST, PORT); $this->ws->set( [ 'worker_num' => WORKER, 'task_worker_num' => TASK, ] ); $this->ws->on("open", [$this,"onOpen"]); $this->ws->on("message", [$this,"onMessage"]); $this->ws->on("close", [$this,"onClose"]); $this->ws->on("task", [$this,"onTask"]); $this->ws->on("finish", [$this,"onFinish"]); $this->ws->start(); } } public function onOpen($ws, $request) { $msg = array( 'msg_type' => 0, ); $this->_pushSysNotice($request->fd); $ws->push($request->fd, json_encode($msg)); } private function _pushOldMsg($fd, $channel, $guild = false){ $m = $this->redis->lRange(CL . $channel,0,CL_MAX_SIZE); $msg = []; foreach($m as $v){ $msg[] = json_decode($v,true); } if(!empty($msg)) $this->ws->task(['fds'=>[$fd],'msg'=>$msg]); $this->redis->lTrim(CL . $channel,0,CL_MAX_SIZE); if($guild){ $g_m = $this->redis->lRange(GCL . $guild,0,CL_MAX_SIZE); $g_msg = []; foreach($g_m as $v){ $g_msg[] = json_decode($v,true); } if(!empty($g_msg)) $this->ws->task(['fds'=>[$fd],'msg'=>$g_msg]); $this->redis->lTrim(GCL . $guild,0,CL_MAX_SIZE); } } private function _pushSysNotice($fd){ $this->redis->select(0); $keys = $this->redis->keys(SM . '*'); $msg = array( 'msg_type' => 3, ); if(!empty($keys)){ foreach($keys as $v){ $s_msg = $this->redis->get($v); $msg['data'] = $s_msg; $this->ws->push($fd, json_encode($msg)); } } $this->redis->select(10); } public function onMessage($ws, $frame) { $data = json_decode($frame->data,true); $ret = []; switch($data['msg_type']){ case 0://初始化 if($this->_checkParam($this->in_param[0], $data)){ $ret = $this->_setConnectInfo($frame->fd, $data); if($data['gid'] > 0) $this->_pushOldMsg($frame->fd,$ret['room_id'],$data['gid']); }else{ $ret = ['msg_type'=>'no param']; } break; case 1://切换频道 if($this->_checkParam($this->in_param[1], $data)){ $ret = $this->_changeChannel($frame->fd, $data); }else{ $ret = ['msg_type'=>'no param']; } break; case 2://聊天 if($this->_checkParam($this->in_param[2], $data)){ $ret = $this->_pushChatInfo($frame->fd, $data); }else{ $ret = ['msg_type'=>'no param']; } break; case 3: break; case 4://公会聊天 if($this->_checkParam($this->in_param[4], $data)){ $ret = $this->_pushChatInfo($frame->fd, $data,true); }else{ $ret = ['msg_type'=>'no param']; } break; default: $ws->push($frame->fd, "error"); break; } echo "fd: {$frame->fd} Message: {$frame->data} \n"; if(!empty($ret)){ $ws->push($frame->fd, json_encode($ret)); } } public function onClose($ws, $fd) { $this->_delChatInfo($fd, true); } public function onTask($ws, $taskId, $workerId, $data) { foreach($data['fds'] as $v){ $this->ws->push($v,json_encode($data['msg'])); } return $taskId; } public function onFinish($ws, $taskId, $data) { echo "task-{$taskId} is end\n"; } //初始化频道计数器 private function _resetChatNum(){ for($i = 1; $i <= CHANNEL_MAX_SIZE; $i++){ $this->redis->zAdd(CNL, 0, CR . $i); } } //获取人数最少频道 private function _getSuggestRoomId(){ $chat_list = $this->redis->zRange(CNL,0,0); $no = substr($chat_list[0],14); if(empty($no) || (int)$no < 1 || (int)$no > CHANNEL_MAX_SIZE){ $no = mt_rand(1,CHANNEL_MAX_SIZE); } return (int)$no; } //连接时设置推荐频道 private function _setConnectInfo($fd, $data){ $channel = $this->_getSuggestRoomId(); $this->_setChannelInfo($fd,$channel); $this->redis->hSet(CF.$fd, 'uid',$data['uid']); $this->redis->hSet(CF.$fd, 'gid',$data['gid']); if(!empty($data['gid'])){ $this->redis->sAdd(GR.$data['gid'], $fd); } return array( 'msg_type' => 1, 'data' => $channel, 'room_id' => $channel, 'code' => 0, 'fd' => $fd, ); } //设置频道相关数据 private function _setChannelInfo($fd, $channel){ //存入fd $this->redis->sAdd(CR . $channel,$fd); //变更计数器 $this->redis->zIncrBy(CNL, 1, CR . $channel); //存入用户频道信息 $this->redis->hSet(CF.$fd, 'channel',(int)$channel); } //校验字段 private function _checkParam($param, $data){ foreach($param as $v){ if(!isset($data[$v]))return false; } return true; } //切换频道 private function _changeChannel($fd, $data){ $this->_delChatInfo($fd); $this->_setChannelInfo($fd,$data['new_room']); $this->_pushOldMsg($fd,$data['new_room']); return array( 'msg_type' => 1, 'data' => $data['new_room'], 'code' => 1, ); } //关闭连接时清除相关内容 private function _delChatInfo($fd, $del = false){ $channel = $this->redis->hget(CF.$fd,'channel'); if(empty($channel)) return true; $this->redis->sRem(CR .$channel, $fd); if($del){ $this->redis->del(CF.$fd); } $this->redis->zIncrBy(CNL, -1, CR . $channel); } //推送聊天信息 private function _pushChatInfo($fd, $data, $guild = false){ if(!$guild){ $user = $this->redis->hGetAll(CF.$fd); $fds = $this->redis->sMembers(CR . $user['channel']); $this->redis->lPush(CL . $user['channel'],json_encode($data)); $type = 2; }else{ $fds = $this->redis->sMembers(GR . $data['gid']); $this->redis->lPush(GCL . $data['gid'],json_encode($data)); $type = 4; } $msg = array( 'msg_type' => $type, 'uid' => $data['uid'], 'name' => $data['name'], 'data' => $data['data'], 'level' => $data['level'], 'head' => $data['head'], 'code' => $type, ); $this->ws->task(['fds'=>$fds,'msg'=>$msg]); return []; } //初始化redis资源 private function _getRedis() { $redis = new Redis(); $redis->connect('127.0.0.1', 6379); return $redis; }}//启动new Ws();
请求示例
{"new_room":8,"old_room":1,"msg_type":1} //切换频道{"level":10,"data":"嗷嗷嗷啊","room_id":1,"msg_type":2,"uid":xxxx,"name":1028,"head":1}//聊天{"gid":xxxx,"uid":xxxx,"msg_type":0} //初始化,其实这块本来想写道open里面但是这样的话需要前端改动,就先这样了。
到此,关于"怎么用swoole + js + redis实现简易聊天室"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!
频道
聊天室
简易
切换
学习
内容
代码
信息
更多
计数器
加密
帮助
接入
实用
接下来
这样的话
上代
人数
公会
前端
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
军营网络安全
网络安全国家一级资质企业
2022年首都网络安全日主题
石景山区威力软件开发推荐
win10网络安全模式退出不了
数据库数字双精度
网站服务器地址隐藏
《网络安全法》法律适用情况
京科通达网络技术有限公司怎么样
军用无线网络技术应用情况
局域网服务器ip如何设置
展厅软件开发免费中文版
软件开发费用可以累计摊销吗
pop3sohu是什么服务器
除了互联网近些年科技在衰退
数据库依赖保护
王秀玉网络技术服务部
深圳市德晟辉网络技术有限公司
exp 网络安全
数据库中无记录是
扬州江苏服务器公司虚拟主机
网络安全应知学问
轻量服务器可以更换ip吗
车载无线网络技术
地下城堡3服务器开放时间
hp服务器出现1786错误
云服务器虚拟主机和网站空间
网站及网络安全管理工作职责
ccd视觉检测软件开发
龙珠超宇宙2服务器连接