聊天服务器(8)用户登录业务
目录
- 登录状态
- 业务层代码
- 数据模型层代码
- 记录用户的连接信息以及线程安全问题
- 客户端异常退出业务
登录状态
登录且状态变为online
业务层代码
#include "chatservice.hpp"
#include "public.hpp"
#include <string>
#include <muduo/base/Logging.h>
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
using namespace muduo;
using namespace std;
//获取单例对象的接口函数
ChatService* ChatService::instance()
{
static ChatService service;
return &service;
}
//注册消息以及对应的Handler回调操作
ChatService::ChatService()
{
//要想实现回调就需要先进行注册,通过绑定对象
_msgHandlerMap.insert({LOGIN_MSG,std::bind(&ChatService::login,this,_1,_2,_3)});
_msgHandlerMap.insert({REG_MSG,std::bind(&ChatService::reg,this,_1,_2,_3)});
}
//获取消息对应的处理器
MsgHandler ChatService::getHandler(int msgid)
{
//记录错误日志,msgid没有对应的事件处理回调
auto it=_msgHandlerMap.find(msgid);
if(it==_msgHandlerMap.end())
{
//返回一个默认的处理器,空操作
return [=](auto a,auto b,auto c){
LOG_ERROR<<"msgid:"<<msgid<<"can not find handler!";
};
}
else
{
return _msgHandlerMap[msgid];
}
}
//处理登录业务
void ChatService::login(const TcpConnectionPtr &conn,json &js,Timestamp)
{
int id=js["id"].get<int>();
string pwd=js["password"];
User user=_userModel.query(id);
if(user.getId()==id&&user.getPwd()==pwd){
if(user.getState()=="online")
{
//该用户已经登录,不允许重复登录
json response;
response["msgid"]=LOGIN_MSG_ACK;
response["errno"]=2;
response["errmsg"]="该账号已经登录,请重新输入新账号";
conn->send(response.dump());
}else{
//登录成功,更新用户状态信息 state offline=>online
user.setState("online");
_userModel.updateState(user);
json response;
response["msgid"]=LOGIN_MSG_ACK;
response["errno"]=0;
response["id"]=user.getId();
response["name"]=user.getName();
conn->send(response.dump());
}
}else{
//该用户不存在,登录失败
json response;
response["msgid"]=LOGIN_MSG_ACK;
response["errno"]=1;
response["errmsg"]="用户名或者密码错误";
conn->send(response.dump());
}
}
//处理注册业务
void ChatService::reg(const TcpConnectionPtr &conn,json &js,Timestamp)
{
string name=js["name"];
string pwd=js["password"];
User user;
user.setName(name);
user.setPwd(pwd);
bool state=_userModel.insert(user);
if(state)
{
//注册成功
json response;
response["msgid"]=REG_MSG_ACK;
response["errno"]=0;
response["id"]=user.getId();
conn->send(response.dump());
}else
{
//注册失败
json response;
response["msgid"]=REG_MSG_ACK;
response["errno"]=1;
conn->send(response.dump());
}
}
数据模型层代码
//更新用户的状态信息
//根据用户号码查询用户信息
bool UserModel::updateState(User user)
{
//组装sql语句
char sql[1024]={0};
sprintf(sql,"update user set state = '%s' where id=%d",user.getState().c_str(),user.getId());
MySQL mysql;
if(mysql.connect()) {
if(mysql.update(sql))
{
return true;
}
}
}
但是问题就是,一登录成功就断开连接了
记录用户的连接信息以及线程安全问题
所以需要保存连接信息
这个表会被多线程访问,所以要考虑它的线程安全问题
上互斥锁!
C++STL里面并没有考虑线程安全问题
数据库的增删改查的并发操作是由MYSQL来保证的,不需要担心去上锁啥的。而线程安全需要保证
大括号表示作用域
客户端异常退出业务
在没有任何响应的情况下,连接突然断开了。比如网络连接问题
如果异常退出,并没有发送合法的json。用户状态如何?
这个业务完成两件事,一个是把存储用户通信连接的哈希表删除该用户的键值对2、将用户在数据库里的状态信息由online变成offline。
当出了大括号之后,锁就自动释放