C++聊天集群服务器4
一、客户端异常退出处理
在chatserviec层增加一个客户端异常退出的处理函数:
因为要保证userConnMap的线程安全,因此在这里用一个智能锁来处理,在作用域结束后会自动释放资源。然后,更新数据库里的在线状态,由online修改为offline,测试效果如图:
登录成功:
此时可以观察数据库的用户在线状态:online
模拟异常退出:
查看数据库在线状态:offline
至此客户端异常状态的业务代码开发及测试完成。
二、点对点通信业务实现
在chatserviec层增加一个一对一聊天的处理函数:
如图,我们维护了一个_userConnMap,如果用户在线就会把他的id和对应的连接加入,然后当其他用户发消息给别人时,就会在维护的这个map里查询,如果在线就会直接把消息转发给他,如果不在线就会把消息存储到离线消息数组里,等对方上线就会发送过去。当然,用户在登录的时候就会更新,在线表map。
在public公共模块添加聊天消息枚举:
开两个shell测试,先登录数据库里的24号用户:
登录另一个:
发送消息:
{"msgid":5,"id":24,"from":"zhangsan","to":15,"msg":"hello!dw!"}
可以看见id为24的用户成功将消息发送给id为15的用户,对方在线直接接收。
测试完成。
三、离线消息存储业务
下面为了方便直接接着上面的测试,后面给出修改代码。我们断开15用户的连接进行测试:
然后再发送给他消息:
然后让15重新上线:
可以看见接收到了离线消息,下面给出代码修改的地方。
添加一个offlinemessagemodel.hpp:
#ifndef OFFLINEMESSAGEMODEL_H
#define OFFLINEMESSAGEMODEL_H
using namespace std;
#include <string>
#include <vector>
//离线消息表的操作接口方法
class OfflineMsgModel
{
public:
//存储用户离线消息
void insert(int userid,string msg);
//删除用户离线的消息
void remove(int userid);
//查询用户的离线消息
vector<string> query(int userid);
};
#endif
实现:
#include "offlinemessagemodel.hpp"
#include "db.h"
// 存储用户离线消息
void OfflineMsgModel::insert(int userid, string msg)
{
//1.组装sql语句
char sql[1024]={0};
sprintf(sql,"insert into offlinemessage values(%d,'%s');",userid,msg.c_str());
MySQL mysql;
if(mysql.connect())
{
mysql.update(sql);
}
}
// 删除用户离线的消息
void OfflineMsgModel::remove(int userid)
{
//1.组装sql语句
char sql[1024]={0};
sprintf(sql,"delete from offlinemessage where userid = %d;",userid);
MySQL mysql;
if(mysql.connect())
{
mysql.update(sql);
}
}
// 查询用户的离线消息
vector<string> OfflineMsgModel::query(int userid)
{
//1.组装sql语句
char sql[1024]={0};
sprintf(sql,"select message from offlinemessage where userid = %d;",userid);
vector<string> vec;
MySQL mysql;
if(mysql.connect())
{
MYSQL_RES* res = mysql.query(sql);
if(res != nullptr)
{
MYSQL_ROW row;
//把userid用户的所有离线消息放入数组,返回
while((row = mysql_fetch_row(res)) != nullptr)
{
vec.push_back(row[0]);
}
mysql_free_result(res);
}
}
return vec;
}
然后在service层添加一个该类:
并且在用户登录的时候从数据库查询其是否有离线消息,有就打包发过去。
至此测试完成。给出目前项目结构图: