怎么用swoole + js + redis实现简易聊天室
发表于:2025-12-01 作者:千家信息网编辑
千家信息网最后更新 2025年12月01日,这篇文章主要介绍"怎么用swoole + js + redis实现简易聊天室",在日常操作中,相信很多人在怎么用swoole + js + redis实现简易聊天室问题上存在疑惑,小编查阅了各式资料,
千家信息网最后更新 2025年12月01日怎么用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安全错误
数据库的锁怎样保障安全
安卓软件开发报告及代码
网络安全素质教育通过率
服务器安全狗还是网站安全狗
苏州戴尔服务器客服电话
关于网络安全议论文的分论点
两个列中重复数据库
初中生网络安全读后感
tbc怀旧服服务器NGA
还原显示数据库正在使用
广州至景科技是互联网公司吗
抢票跟服务器在哪里有关系吗
全球软件开发网
软件开发和应用技术就业前景
代号探戈第四关服务器核心
学软件开发难度大么
计算机网络技术对金融
国泰安数据库权威吗
农村工作局网络安全应急预案
商丘市网络安全和信息化会议
服务器安全性设置在哪里
合阳县崇雨网络技术有限公司
服务器集群物理端
服务器报警400是什么意思
医保业务网络安全管理制度有哪些
戴尔服务器4合一
数据库原理教程pdf
网络安全检查频次
南昌ios软件开发多少钱
网络安全领域为什么人少
铁路 数据库