C++聊天集群服务器4

一、客户端异常退出处理

​ 在chatserviec层增加一个客户端异常退出的处理函数:

image-20231128133818477

​ 因为要保证userConnMap的线程安全,因此在这里用一个智能锁来处理,在作用域结束后会自动释放资源。然后,更新数据库里的在线状态,由online修改为offline,测试效果如图:
​ 登录成功:

image-20231128134440224

​ 此时可以观察数据库的用户在线状态:online

image-20231128134534523

​ 模拟异常退出:

image-20231128134555018

​ 查看数据库在线状态:offline

image-20231128134625010

​ 至此客户端异常状态的业务代码开发及测试完成。

二、点对点通信业务实现

​ 在chatserviec层增加一个一对一聊天的处理函数:

image-20231129102418349

​ 如图,我们维护了一个_userConnMap,如果用户在线就会把他的id和对应的连接加入,然后当其他用户发消息给别人时,就会在维护的这个map里查询,如果在线就会直接把消息转发给他,如果不在线就会把消息存储到离线消息数组里,等对方上线就会发送过去。当然,用户在登录的时候就会更新,在线表map。

image-20231129103150728

​ 在public公共模块添加聊天消息枚举:

image-20231129102636806

​ 开两个shell测试,先登录数据库里的24号用户:

image-20231129103514132

​ 登录另一个:

image-20231129103822425

​ 发送消息:

​ {"msgid":5,"id":24,"from":"zhangsan","to":15,"msg":"hello!dw!"}

image-20231129104316604

​ 可以看见id为24的用户成功将消息发送给id为15的用户,对方在线直接接收。

​ 测试完成。

三、离线消息存储业务

​ 下面为了方便直接接着上面的测试,后面给出修改代码。我们断开15用户的连接进行测试:

image-20231129104508351

​ 然后再发送给他消息:

image-20231129104548151

​ 然后让15重新上线:

image-20231129104641686

​ 可以看见接收到了离线消息,下面给出代码修改的地方。

​ 添加一个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层添加一个该类:

image-20231129105120910

​ 并且在用户登录的时候从数据库查询其是否有离线消息,有就打包发过去。

image-20231129105310156

​ 至此测试完成。给出目前项目结构图:

image-20231129105338213

posted @ 2023-11-29 10:55  桂洛克船长  阅读(17)  评论(0编辑  收藏  举报