C++搭建集群聊天室:用户单聊及离线消息处理功能实现
Posted 看,未来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++搭建集群聊天室:用户单聊及离线消息处理功能实现相关的知识,希望对你有一定的参考价值。
单聊
单聊功能其实很简单的,就是数据包的发送,接收。
public.h 现状:
#ifndef PUBLIC_H_
#define PUBLIC_H_
enum EnMsgType{
LOGIN_TYPE = 1, //正常登录
LOGIN_MSG_ACK, //登录相应消息
REG_TYPE, //正常注册
REG_MSG_ACK, //注册相应消息
ONE_CHAT_MSG, //一对一聊天消息
GROUP_CHAT_MSG, //群聊聊天消息
};
#endif
单聊,在chatservice.cpp 里面加一个函数,头文件自行修改。
//一对一聊天
void ChatService::onechat(const TcpConnectionPtr &conn,json &js,Timestamp time){
int toid = js["to"].get<int>();
// bool userstate = false;
//开辟锁的作用域
{
lock_guard<mutex> lock(_connMutex);
auto it = _userConnMap.find(toid);
if(it != _userConnMap.end()){
//用户在线,转发消息
it->second->send(js.dump());
return;
}
}
// 有可能在发送的时候,连接就给断了
// if(userstate){ //用户在线,转发消息
// }
// else{ //用户不在线,存储离线消息
// }
//存储离线消息
_offlineMsgmodel.insert(toid,js.dump());
}
直接聊就这样。
比较复杂一点的是处理离线消息。
离线消息处理
开一个专门处理离线消息的文件,offlinemessagemodel.cpp,头文件配上。
#ifndef OFFLINEMESSAGEMODEL_H_
#define OFFLINEMESSAGEMODEL_H_
#include<string>
#include<vector>
using namespace std;
class OfflineMessageModel{
public:
//存储用户离线消息
void insert(int user_id,string msg);
//删除用户离线消息
void remove(int userid);
//读取用户离线消息
vector<string> query(int userid);
private:
};
#endif
offlinemessagemodel.cpp 实现:
#include "db.hpp"
#include "offlinemessagemodel.hpp"
//存储用户离线消息
void OfflineMessageModel::insert(int userid, string msg){
char sql[128] = {0};
sprintf(sql, "insert into offlinemessage values(%d, '%s')", userid, msg.c_str());
mysql mysql;
if(mysql.connect()){
mysql.update(sql);
}
}
//删除用户离线消息
void OfflineMessageModel::remove(int userid){
char sql[128] = {0};
sprintf(sql,"delete from OfflineMessage where userid = %d",userid);
MySQL mysql;
if(mysql.connect()){
mysql.update(sql);
}
}
//读取用户离线消息
vector<string> OfflineMessageModel::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;
while((row = mysql_fetch_row(res)) != nullptr){
vec.push_back(row[0]);
}
mysql_free_result(res);
}
}
return vec;
}
离线消息调用逻辑
1、在发送消息的时候判断对方是否在线,不在线则存储离线消息。
2、在登录的时候加载离线消息,一般消息会很多,所以用容器来存储。
3、容器选择vector,便于直接序列化/反序列化。
第一、三点在上面展示了,第二点:
void ChatService::login(const TcpConnectionPtr &conn,json &js,Timestamp time){
int id = js["id"].get<int>();
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!";
//查询用户是否有离线消息
vector<string> vec = _offlineMsgmodel.query(id);
if(!vec.empty()){
response["offlinemsg"] = vec;
//清空离线消息
_offlineMsgmodel.remove(id);
}
conn->send(response.dump());
}
else
{
//添加作用域,限制锁的粒度
{
lock_guard<mutex> lock(_connMutex);
//记录用户连接
_userConnMap.insert({id,conn});
}
// 登录成功,更新用户状态信息 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"] = "id or password is invalid!";
conn->send(response.dump());
}
}
前面代码修改
发现前面的SQL语句中将表 User 写成了 user,这里需要改一下
以上是关于C++搭建集群聊天室:用户单聊及离线消息处理功能实现的主要内容,如果未能解决你的问题,请参考以下文章