问题描述
在做聊天服务器用户登录测试时,在登录成功后,在终端输入了 ctrl+z 结束了会话,导致客户端异常推出,之后该用户便一直无法正常登录。
问题原因
在用户登录方法中,考虑到了用户重复登录的问题,所以在用户登录的时候会先判断用户的状态 state是‘online’还是‘offline’ ,如果是online就说明用户已经登录在线了,就不允许再次登录,如下:
if(user.getState()=="online")
{
//该用户以及登录,不允许重复登录
json response;
response["msgid"]=LOGIN_MSG_ACK;
response["error"]=2;
response["errmsg"]="该账号已经登录";
conn->send(response.dump());
}
因为在代码中没有考虑异常退出这种情况,所以当用户异常退出后,其在数据库中的状态state没有从online修改为offline,导致下次再登录的时候,提示已经登录。
解决问题
首先整理当一个用户退出时,需要做哪些操作
- 将该用户从当前在线用户组中删除
- 更新用户在数据库中的状态信息:将该用户数据库user表中的state字段置为offline
在业务处理类中添加异常退出的处理函数:
//处理客户端异常退出
void ChatService::clientCloseException(const TcpConnectionPtr& conn)
{
User user;
{
lock_guard<mutex> lock(_connMutex);
for(auto it=_userConnMap.begin(); it!=_userConnMap.end();++it)
{
if(it->second == conn){
user.setId(it->first);

_userConnMap.erase(it);
break;
}
}
}
//更新数据库
user.setState("offline");
_userModel.updateState(user);
}
在处理连接的回调函数中加上对异常退出处理的调用:
测试
首先还没有登录时,查看数据库中zhang san的状态,登录后的状态,已经异常退出后的状态:
可以看到在异常退出的时候又访问了一次数据库,达到了预期。