chat集群聊天室项目 代码+讲解(二):业务模块

using namespace std;

using namespace muduo;

ChatService* ChatService::instance(){

static ChatService service;

return &service;

}

//注册消息以及对应的回调操作

ChatService::ChatService(){

_msgHanderMap.insert({LOGIN_TYPE,std::bind(&ChatService::login,this,_1,_2,_3)});

_msgHanderMap.insert({REG_TYPE,std::bind(&ChatService::reg,this,_1,_2,_3)});

···

}

//获取存储消息id和对应的处理方法

MsgHandler ChatService::getHandle(int msgid){

//日志记录

auto it = _msgHanderMap.find(msgid);

if(it == _msgHanderMap.end()){

//返回一个lambda表达式,返回一个默认的空处理器,防止业务挂掉,后可做平滑升级处理

return [=](const TcpConnectionPtr &conn,json &js,Timestamp time){

LOG_ERROR<<“msgid:”<<msgid<<“can not find handle!”;

};

}

else{

return _msgHanderMap[msgid];

}

}

void ChatService::login(const TcpConnectionPtr &conn,json &js,Timestamp time){

int id = js[“id”].get();

string pwd = js[“password”];

User user = _usermodel.query(id);

if (user.getID() == id && user.getpassword() == pwd)

{

if (user.getstate() == “online”)

{

// 该用户已经登录,不允许重复登录

json response;

response[“msgid”] = LOGIN_MSG_ACK;

response[“errno”] = 2;

response[“errmsg”] = “this account is using, input another!”;

conn->send(response.dump());

}

else

{

//添加作用域,限制锁的粒度

{

lock_guard lock(_connMutex);

//记录用户连接

_userConnMap.insert({id,conn});

}

// 登录成功,更新用户状态信息 state offline=>online

user.setstate(“online”);

_usermodel.updateState(user); // !!! Single stepping until exit from function _IO_default_xsputn,

json response;

response[“msgid”] = LOGIN_MSG_ACK;

response[“errno”] = 0;

response[“id”] = user.getID();

response[“name”] = user.getname();

//查询用户是否有离线消息

vector vecofflinemsg = _offlineMsgmodel.query(id);

if(!vecofflinemsg.empty()){

response[“offlinemsg”] = vecofflinemsg;

//清空离线消息

_offlineMsgmodel.remove(id);

}

vector uservec = _friendmodel.query(id);

if(!uservec.empty()){

vector vecfriend;

for(User &user:uservec){

json js;

js[“id”] = user.getID();

js[“name”] = user.getname();

js[“state”] = user.getstate();

vecfriend.push_back(js.dump());

}

response[“friends”] = vecfriend;

}

conn->send(response.dump());

}

}

else

{

// 该用户不存在,用户存在但是密码错误,登录失败

json response;

response[“msgid”] = LOGIN_MSG_ACK;

response[“errno”] = 1;

response[“errmsg”] = “id or password is invalid!”;

conn->send(response.dump());

}

}

void ChatService::reset(){

//把所有online状态的用户转为offline

_usermodel.resetstate();

}


讲解


为什么要设置单例

难道单例就只能拿来保证对象的单一性吗?

如果是为了保证对象的单一性,那取对象的时候就应该上个锁了,甚至是像“懒汉”那样上两个锁了。

在网络模块儿中,是这么写的:

void ChatServer::onMessage(const TcpConnectionPtr &conn, Buffer *buff, Timestamp time){

···

//通过msgid获取业务回调,进行网络模块和任务模块之间的解耦合

auto msgHandler = ChatService::instance()->getHandle(js[“msgid”].get());

//回调消息绑定好的事件处理器,执行相应的业务处理

msgHandler(conn,js,time);

···

就取个任务的事情,任务取完就甩手给channel去办事儿了。

难道每次我来取个任务还要 new 一下吗?

那为什么不在ChatServer里面放一个Chatservice chatservice_ 对象呢?

那为什么就非要加上这么一层耦合呢?


MsgHandler 的设计

//通过msgid获取业务回调,进行网络模块和任务模块之间的解耦合

auto msgHandler = ChatService::instance()->getHandle(js[“msgid”].get());

//回调消息绑定好的事件处理器,执行相应的业务处理

msgHandler(conn,js,time);


_msgHanderMap.insert({LOGIN_TYPE,std::bind(&ChatService::login,this,_1,_2,_3)});

_msgHanderMap.insert({REG_TYPE,std::bind(&ChatService::reg,this,_1,_2,_3)});


//获取存储消息id和对应的处理方法

MsgHandler ChatService::getHandle(int msgid)

{

auto it = _msgHanderMap.find(msgid);

if(it == _msgHanderMap.end()){

//返回一个lambda表达式,返回一个默认的空处理器,防止业务挂掉,后可做平滑升级处理

return [=](const TcpConnectionPtr &conn,json &js,Timestamp time){

LOG_ERROR<<“msgid:”<<msgid<<“can not find handle!”;

};

}

else{

return _msgHanderMap[msgid];

最后

很多程序员,整天沉浸在业务代码的 CRUD 中,业务中没有大量数据做并发,缺少实战经验,对并发仅仅停留在了解,做不到精通,所以总是与大厂擦肩而过。

我把私藏的这套并发体系的笔记和思维脑图分享出来,理论知识与项目实战的结合,我觉得只要你肯花时间用心学完这些,一定可以快速掌握并发编程。

不管是查缺补漏还是深度学习都能有非常不错的成效,需要的话记得帮忙点个赞支持一下

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值