本节来实现C++集群聊天服务器项目中的点对点聊天业务,一起来试试吧
一、点对点聊天业务
聊天服务器中一个重要的功能就是实现点对点聊天,客户端发送的信息包含聊天业务msgid、自身
的id和姓名、聊天对象的id号以及聊天信息,例如:
{"msgid":5,"id":13,"name":"zhang san","to":15,"msg":"Hello,Boy!"}
id号为13的张三用户要与id号为15的用户进行 点对点聊天业务,发送消息为Hello,Boy!
如果要聊天,那便是双方的
{"msgid":5,"id":15,"name":"lisi","to":13,"msg":"Hello,Hello."}
id号为15的李四用户与id号为13的用户聊天,发送消息为Hello,Hello.
二、点对点业务步骤
(1)从json传来的数据中,获取聊天对象的id号
int to_id = js["to"].get<int>();
(2)点对点聊天,必须双方在线,如果不在线,则发送离线消息。因此需判断聊天对象是否在线,即是否在存储用户的通信连接的哈希表_userConnMap中,遍历哈希表查找在线用户id是否为聊天对象id,这里需保证线程安全,加锁
lock_guard<mutex>lock(_connMutex);
auto it = _userConnMap.find(to_id);
<1>如果聊天用户在线
服务器作为中转,主动推送消息给聊天对象用户
if(it!=_userConnMap.end()){
//to_id在线,转发消息,服务器主动推动消息给to_id用户
it->second->send(js.dump());
return ;
}
<2>如果聊天用户不在线,转而处理离线消息
底层数据库中,有一张offlinemessage表存储了离线消息
与处理user表类似,我们定义offlineMsgModel类处理离线消息业务,实现插入离线消息、删除离线消息、查询离线消息功能
class offlineMsgModel{
public:
//存储用户的离线消息
void insert(int userid,string msg);
//删除用户的离线消息
void remove(int userid);
//查询用户的离线消息
vector<string> query(int userid);
};
因此,当点对点聊天发现聊天对象不在线时,我们将json对象序列化后存入底层数据库中
因此,存储离线消息函数如下:
// 存储用户的离线消息
void offlineMsgModel::insert(int userid, string msg)
{
char sql[1024] = {0};
sprintf(sql, "insert into offlinemessage values(%d, '%s')", userid, msg.c_str());
MySQL mysql;
if (mysql.connect())
{
mysql.update(sql);
}
}
(3)第(八)节用户登录模块,用户登录后需查看是否有对应的离线消息,如果有服务器就将数据库中存储的离线消息推送给相应的客户端,然后删除库中存储的离线消息
<1>查看用户是否有离线消息
实现offlineMsgModel的查询函数,用一个vector容器来接收字符串消息
// 查询用户的离线消息
vector<string> offlineMsgModel::query(int userid)
{
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)
{
// 把userid用户的所有离线消息放入vec中返回
MYSQL_ROW row;
while((row = mysql_fetch_row(res)) != nullptr)
{
vec.push_back(row[0]);
}
mysql_free_result(res);
return vec;
}
}
return vec;
}
</