[集群聊天服务器]----(三)ChatService模块,解耦网络模块和业务模块

devtools/2024/9/22 10:53:13/

接着上一节[集群聊天服务器]----(二)利用muduo网络库实现网络模块ChatServer的剖析,我们发现需要对网络模块和业务模块进行解耦,引入了ChatService类,接下来我们来看一下业务模块ChatService类具体做了什么。

成员变量

//存储消息id和其对应的事件处理方法 事先就添加好的,不需要考虑线程安全问题
unordered_map<int,MsgHandler> _msgHandlerMap;//定义互斥锁,保证_userConnMap的线程安全
mutex _connMutex;//存储在线用户的通信连接 随着用户的上下线 而改变,需要考虑线程安全问题
unordered_map<int,TcpConnectionPtr> _userConnMap;//数据操作类对象
UserModel _userModel;OfflineMsgModel _offlineMsgModel;FriendModel _friendModel;GroupModel _groupModel;//redis操作对象
Redis _redis;

成员函数

 //获取单例对象的接口函数static ChatService* instance();//处理登录业务void login(const TcpConnectionPtr& conn, json &js, Timestamp time);//处理注册业务void reg(const TcpConnectionPtr& conn, json &js, Timestamp time);// 处理注销业务void loginout(const TcpConnectionPtr &conn, json &js, Timestamp time);//一对一聊天业务void oneChat(const TcpConnectionPtr& conn, json &js, Timestamp time);//添加好友业务void addFriend(const TcpConnectionPtr& conn, json &js, Timestamp time);// 创建群组业务void createGroup(const TcpConnectionPtr &conn, json &js, Timestamp time);// 加入群组业务void addGroup(const TcpConnectionPtr &conn, json &js, Timestamp time);// 群组聊天业务void groupChat(const TcpConnectionPtr &conn, json &js, Timestamp time);//服务器异常退出,业务重置void reset();//获取消息对应的处理器MsgHandler getHandler(int msgid);//处理客户端异常退出void clientCloseException(const TcpConnectionPtr &conn);// 从redis消息队列中获取订阅的消息void handleRedisSubscribeMessage(int, string);

处理消息的事件回调类型

using MsgHandler = std :: function<void(const TcpConnectionPtr& conn, json &js, Timestamp)>;

定义了一个MsgHandler 模板类型,用于处理各类回调

构造函数

ChatService()构造函数被私有化,并给出了单例模式接口,外界只能调用ChatService的静态方法。

//获取单例对象的接口函数
static ChatService* instance();ChatService *ChatService::instance()
{static ChatService service;return &service;
}
  • static变量会保证全局唯一,多个实例共享一个static变量,若该static变量已经初始化过,就不会再次初始化。static修饰过的成员变量和方法独立于类的任何对象。并且C++ 11 保证 static 成员变量是线程安全的。
  • 注册消息以及对应的handler回调操作
ChatService::ChatService()
{_msgHandlerMap.insert({LOGIN_MSG, std::bind(&ChatService::login, this, _1, _2, _3)});_msgHandlerMap.insert({LOGINOUT_MSG, std::bind(&ChatService::loginout, this, _1, _2, _3)});_msgHandlerMap.insert({REG_MSG, std::bind(&ChatService::reg, this, _1, _2, _3)});_msgHandlerMap.insert({ONE_CHAT_MSG, std::bind(&ChatService::oneChat, this, _1, _2, _3)});_msgHandlerMap.insert({ADD_FRIEND_MSG, std::bind(&ChatService::addFriend, this, _1, _2, _3)});_msgHandlerMap.insert({CREATE_GROUP_MSG, std::bind(&ChatService::createGroup, this, _1, _2, _3)});_msgHandlerMap.insert({ADD_GROUP_MSG, std::bind(&ChatService::addGroup, this, _1, _2, _3)});_msgHandlerMap.insert({GROUP_CHAT_MSG, std::bind(&ChatService::groupChat, this, _1, _2, _3)});/****/}
}
  • 其中_msgHandlerMap是存储消息id和其对应的事件处理方法 提前将各个业务模块的代码放入了容器中,其内部有用哈希表记录了各种msgid所对应的回调函数。并且是事先就添加好的,不需要考虑线程安全问题。
unordered_map<int,MsgHandler> _msgHandlerMap;
  • 解耦两个模块的重点就在 ChatServer ::onMessage代码中,调用了getHandler()
// ChatServer.cpp
auto msgHandler = ChatService::instance()->getHandler(js["msgid"].get<int>());//ChatService.cpp
MsgHandler ChatService::getHandler(int msgid)
{// 记录错误日志 msgid没有对应的事件处理回调auto it = _msgHandlerMap.find(msgid);if (it == _msgHandlerMap.end()){return [=](const TcpConnectionPtr &conn, json &js, Timestamp){LOG_ERROR << "msgid:" << msgid << " can not find handler!";};}else{return _msgHandlerMap[msgid];}
}
  • _msgHandlerMap中根据客户端指定的msgid序号进行查找,如果找到了返回_msgHandlerMap[msgid];msgHandler(conn,js,time);进行处理回调;如果没有找到就返回一个默认的回调,即打印一个日志,通知客户端没有相关回调。

好了~关于集群聊天服务器项目的网络模块和业务模块解耦就到此结束了,封装了回调函数,这个思想也是很重要的!因为需要mysql才能对每个业务模块进行剖析,所以下一节我们先来剖析mysql的封装使用,我们下一节见 ~


http://www.ppmy.cn/devtools/42585.html

相关文章

【Python】—— 公共的方法

目录 &#xff08;一&#xff09;公共操作 1.1 公共操作之运算符加号 1.2 公共操作之运算符乘号 1.3 公共操作之运算符判断数据是否存在 &#xff08;二&#xff09;公共方法 2.1 公共方法-len 2.2 公共方法-del 2.3 公共方法-max和min 2.4 公共方法-range 2.5 公共方…

微信小程序 - - - - - 使用TDesign库(微信小程序UI库)

使用TDesign库 1. 初始化依赖2. 安装TDesgin3. npm构建3. 修改 app.json 1. 初始化依赖 npm init -y2. 安装TDesgin yarn add tdesign-miniprogram -S --productionor npm install tdesign-miniprogram -S --production3. npm构建 3. 修改 app.json 将 app.json 中的 “styl…

vue中数据已经改变了,但是table里面内容没更新渲染!

解决方案&#xff1a; 给table或者el-table标签上添加一个动态key值&#xff0c;只要数据发生改变&#xff0c;key值变动一下即可 标签上&#xff1a; :key“timeStamp” 初始data&#xff1a;timeStamp:0, 更新数据&#xff1a;this.timeStamp 这样每次更新数据&#xff…

el-table自定义表头数据不更新

我的表头是有三层的&#xff0c;中间一层展示对应的数据&#xff0c;所以需要自定义&#xff0c;官方的文档显示的写法如下&#xff1a; <el-table-column><template slot“header”><div>{{dayData.supply}}、{{dayData.use}}</div></template>…

多电脑共享鼠标键盘

由于要在两个电脑之间共用一套鼠标键盘&#xff0c;所以在此记录一下。 mouse without borders Mouse without Borders 是一款免费的 Windows 工具&#xff0c;允许你在多台电脑之间共享鼠标和键盘。 安装与配置步骤 下载和安装&#xff1a; 前往 Mouse without Borders 官…

肯尼亚大坝决堤反思:强化大坝安全监测的必要性

一、背景介绍 近日&#xff0c;肯尼亚发生了一起严重的大坝决堤事件。当地时间4月29日&#xff0c;肯尼亚内罗毕以北的一座大坝决堤&#xff0c;冲毁房屋和车辆。当地官员称&#xff0c;事故遇难人数已升至71人。这起事件再次提醒我们&#xff0c;大坝安全无小事&#xff0c;监…

Git命令汇总

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

目前流行的前端框架有哪些?

目前流行的前端框架有很多&#xff0c;它们可以帮助开发者快速构建高质量的前端应用程序。本文将介绍一些目前比较受欢迎的前端框架&#xff0c;并分析它们的优缺点。 React React 是一个由 Facebook 开发的开源前端JavaScript库&#xff0c;用于构建用户界面&#xff0c;尤其…