C++搭建集群聊天室(十二):用户单聊及离线消息处理功能实现
【摘要】 单聊单聊功能其实很简单的,就是数据包的发送,接收。public.h 现状:#ifndef PUBLIC_H_#define PUBLIC_H_enum EnMsgType{ LOGIN_TYPE = 1, //正常登录 LOGIN_MSG_ACK, //登录相应消息 REG_TYPE, //正常注册 REG_MSG_ACK, //注册相应消息 ...
单聊
单聊功能其实很简单的,就是数据包的发送,接收。
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!";
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();
//查询用户是否有离线消息
vector<string> vec = _offlineMsgmodel.query(id);
if(!vec.empty()){
response["offlinemsg"] = vec;
//清空离线消息
_offlineMsgmodel.remove(id);
}
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,这里需要改一下
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)