[集群聊天服务器]----(八)群组类、群组操作接口以及业务模块之创建群组,加入群组以及群组聊天

news2025/10/28 3:58:23

接着上文关于[集群聊天服务器]----(七)业务模块之一对一聊天、添加好友函数、好友类以及离线消息类的剖析。本章将对创建群组,加入群组以及群组聊天业务进行剖析。

群类

类似于User类,构建了Group类

#ifndef GROUP_H
#define GROUP_H

#include "groupuser.hpp"
#include <string>
#include <vector>
using namespace std;

//User表的ORM类
class Group
{
public:
    Group(int id = -1, string name = "", string desc = "")
    {
        this->id = id;
        this->name = name;
        this->desc = desc;
    }
    
    void setId(int id) {this->id=id;}
    void setName(string name) {this->name=name;}
    void setDesc(string desc) {this->desc=desc;}


    int getId() {return this->id;}
    string getName() {return this->name;}
    string getDesc() {return this->desc=desc;}  //组功能描述
    vector<GroupUser> &getUsers() {return this->users;}


private:
    int id;
    string name;
    string desc;
    vector<GroupUser> users; //组成员
};

#endif
  • 群的id初始默认为-1,设置/获取群id,群名称以及群用途函数

GroupUser类

GroupUser为群组用户,继承了User类,多了一个role角色信息,从User类直接继承,复用User的其他信息

void setRole(string role) {this->role = role;}
string getRole() {return this->role;}

//派生类的特殊变量 role角色
string role;

群组信息的操作接口

// 创建群组
bool createGroup(Group &group);

// 加入群组
void addGroup(int userid, int groupid, string role);

// 查询用户所在群组信息
vector<Group> queryGroups(int userid);

// 根据指定的groupid查询群组用户id列表,除userid自己,主要用户群聊业务给群组其它成员群发消息
vector<int> queryGroupUsers(int userid, int groupid);

创建群组函数

bool GroupModel::createGroup(Group &group)
{
    char sql[1024] = {0};
    sprintf(sql, "insert into allgroup(groupname, groupdesc) values('%s', '%s')",
            group.getName().c_str(), group.getDesc().c_str());

    MySQL mysql;

    // 连接数据库
    if (mysql.connect())
    {
        // 更新数据库语句
        if (mysql.update(sql))
        {
            group.setId(mysql_insert_id(mysql.getConnection()));
            return true;
        }
    }
    return false;
}
  • 组装sql语句,根据群名称,群作用在allgroup表插入相关消息;
  • 连接数据库,并进行更新,并返回群id

加入群组函数

void GroupModel::addGroup(int userid, int groupid, string role)
{
    char sql[1024] = {0};
    sprintf(sql, "insert into groupuser values(%d,%d,'%s')",
            groupid,userid,role.c_str());

    MySQL mysql;

    // 连接数据库
    if (mysql.connect())
    {
        // 更新数据库语句
        mysql.update(sql);
    }
}
  • 组装sql语句,根据群id,用户id,以及群内角色在allgroup表插入相关消息;
  • 连接数据库,并进行更新,并返回群id

查询用户所在群组信息

vector<Group> GroupModel::queryGroups(int userid)
{
    char sql[1024] = {0};
    sprintf(sql,"select a.id,a.groupname,a.groupdesc from allgroup a inner join \
        groupuser b on a.id = b.groupid where b.userid=%d",userid);
    
    vector<Group> groupVec;

    MySQL mysql;

    if (mysql.connect())
    {
        // 更新数据库语句
        MYSQL_RES *res = mysql.query(sql); // 指针 内部动态内存开辟 需要释放资源
        if (res != nullptr)
        {
            // 获取行 根据主键查
            MYSQL_ROW row ;
            while((row = mysql_fetch_row(res)) != nullptr) 
            {
                Group group;
                group.setId(atoi(row[0]));
                group.setName(row[1]);
                group.setDesc(row[2]);
                groupVec.push_back(group);
            }

            mysql_free_result(res);
        }
    }

    for(Group &group: groupVec)
    {
        sprintf(sql,"select a.id,a.name,a.state,b.grouprole from user a \
            inner join groupuser b on b.userid = a.id where b.groupid=%d", group.getId());
        
        MYSQL_RES *res = mysql.query(sql);
        if (res != nullptr)
        {
            // 获取行 根据主键查
            MYSQL_ROW row ;
            while((row = mysql_fetch_row(res)) != nullptr) 
            {
                GroupUser user;
                user.setId(atoi(row[0]));
                user.setName(row[1]);
                user.setState(row[2]);
                user.setRole(row[3]);
                group.getUsers().push_back(user);
            }

            mysql_free_result(res);
        }
        
    }
    return groupVec;
}
  • 组装sql语句,根据用户id在allgroup表和groupuser表中进联合查找,寻找用户所在的组;
  • 根据sql语句,调用MySQL::query()语句进行查找好友,然后调用mysql_fetch_row()函数,查找对应的行,row是MYSQL_ROW类型,可以根据下标找到对应的值,并把用户对应的组Group类放入groupVec中;
  • 根据groupVec中,对组内的成员姓名,id以及状态和群内角色进行查找,对应的GroupUser类进行返回
  • 注意释放资源

查找群内除userid以外的用户

vector<int> GroupModel::queryGroupUsers(int userid, int groupid)
{
    char sql[1024] = {0};
    sprintf(sql,"select userid from groupuser where groupid = %d and userid != %d",groupid,userid);
    
    vector<int> idVec;

    MySQL mysql;

    if (mysql.connect())
    {
        // 更新数据库语句
        MYSQL_RES *res = mysql.query(sql); // 指针 内部动态内存开辟 需要释放资源
        if (res != nullptr)
        {
            // 获取行 根据主键查
            MYSQL_ROW row ;
            while((row = mysql_fetch_row(res)) != nullptr) 
            {
                idVec.push_back(atoi(row[0]));
            }

            mysql_free_result(res);
        }
    }
    return idVec;
}
  • 组装sql语句,根据userid在groupuser表查找其余用户id;
  • 根据sql语句,调用MySQL::query()语句进行查找好友,然后调用mysql_fetch_row()函数,查找对应的行,row是MYSQL_ROW类型,可以根据下标找到对应的值,并把用户放入idVec中返回;
  • 注意释放资源

创建群组

当客户端输入msgid=CREATE_GROUP_MSG时,ChatService::ChatService()中会回调ChatService::createGroup()函数进行处理:

void ChatService::createGroup(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    int userid = js["id"].get<int>();
    string name = js["groupname"];
    string desc = js["groupdesc"];

    // 存储新创建的群组信息
    Group group(-1, name, desc);
    if (_groupModel.createGroup(group))
    {
        // 存储群组创建人信息
        _groupModel.addGroup(userid, group.getId(), "creator");
    }
}
  • 通过 JSON 对象反序列结果,寻找用户id userid对应的值,groupname以及groupdesc
  • 创建Group类,并调用 GroupModel::createGroup()创建群,角色为creator;
  • 根据创建的群组,设置群id

加入群组

当客户端输入msgid=ADD_GROUP_MSG时,ChatService::ChatService()中会回调ChatService::addGroup()函数进行处理:

void ChatService::addGroup(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    int userid = js["id"].get<int>();
    int groupid = js["groupid"].get<int>();
    _groupModel.addGroup(userid, groupid, "normal");

}
  • 根据userid以及要加入的groupid,调用GroupModel::addGroup()函数加入群,角色默认为normal;

群组聊天

当客户端输入msgid=GROUP_CHAT_MSG时,ChatService::ChatService()中会回调ChatService::groupChat()函数进行处理:

void ChatService::groupChat(const TcpConnectionPtr &conn, json &js, Timestamp time)
{
    int userid = js["id"].get<int>();
    int groupid = js["groupid"].get<int>();
    vector<int> useridVec = _groupModel.queryGroupUsers(userid,groupid);
 
    lock_guard<mutex> lock(_connMutex); // 线程安全
    for(int id : useridVec)
    {
       
        auto it = _userConnMap.find(id);
        if (it != _userConnMap.end())
        {
            // id 在线 转发消息 服务器主动推送消息给toid用户
            it->second->send(js.dump());
        }
        else
        {
            User user = _userModel.query(id);
            //在另一台电脑上
            if (user.getState() == "online")
            {
                _redis.publish(id, js.dump());
            }
            else
            {
                // id 不在线 存储离线消息
                _offlineMsgModel.insert(id, js.dump());
            }        
        }
    }
}
  • 通过 JSON 对象反序列结果,寻找用户id以及群id对应的值,找到用户想要对话的群,并在_groupModel中进行查找群内其余成员,并放入useridVec中;
  • _userConnMap查找用户是否存在;
  • 如果用户在一台主机并且处于在线状态,就发送想要发送的消息;
  • 如果不在同一台主机,根据id调用_userModel在user表中进行查看对方是否在线,如果在线就通过redis发布消息
  • 不在线就存储其离线消息

好了~ 关于群组类、群组操作接口以及业务模块之创建群组,加入群组以及群组聊天的剖析就到此结束了,服务端的开发也到此结束了,接下来我们会剖析客户端的实现,下一节见~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1700299.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ARM+FPGA+NVIDIA AI摄像头软硬件定制

拥有资深ISP图像技术团队&#xff0c;是英伟达、地平线等合作伙伴&#xff0c;我们的团队掌握目前市面上大部分车载平台的ISP图像画质服务能力&#xff0c;能自主开发图像ISP和增强算法。我们具有多名经验丰富光学设计专家&#xff0c;掌握车载模组光学设计能力&#xff0c;资深…

数据结构——链表——模板类实现双向链表——先完成再完美——持续更

链表&#xff1a;概念&#xff0c;实现&#xff0c;《数据结构》这里实现是基于模板的 C语言基础&#xff0c;指针&#xff0c;引用。模板。《CPrimer》有些进阶用法放在语言学习的目录 LeetCode应用&#xff0c;会更新在LeetCode150&#xff0c;目前这个系列先暂停&#xff0c…

遇见问题-VMware虚拟机打开运行一段时间后卡死

1.问题原因 因为Windows自带的虚拟化软件Hyper-V与VMware存在冲突。 2.关闭Hyper-V 1.打开【控制面板】-【程序和功能】-【启用或关闭Windows功能】3.关闭HV主机服务 1.右击计算机-》管理-》服务和应用名称-》服务-》找到HV主机服务-》右击属性停止服务 -》启动类型设置为禁…

NASA数据集——阿尔法喷气式大气实验二氧化碳和甲烷数据

Alpha Jet Atmospheric eXperiment Carbon Dioxide and Methane Data 阿尔法喷气式大气实验二氧化碳和甲烷数据 简介 Alpha Jet Atmospheric eXperiment (AJAX) 是美国国家航空航天局艾姆斯研究中心与 H211, L.L.C. 公司的合作项目&#xff0c;旨在促进对加利福尼亚、内华达…

asp.net core接入prometheus2-自定义指标

前提 了解一下asp.net core接入prometheus快速入门 https://blog.csdn.net/qq_36437991/article/details/139064138 新建.net 8空web项目 安装下面三个包 <PackageReference Include"OpenTelemetry.Exporter.Prometheus.AspNetCore" Version"1.8.0-rc.1&…

【软件设计师】计算机组成原理

1、数据的表示 1.1 进制转换 整型有4种进制形式&#xff1a; 1.十进制&#xff08;D&#xff09;&#xff1a; 都是以0-9这九个数字组成&#xff0c;不能以0开头。 2.二进制&#xff08;B&#xff09;&#xff1a; 由0和1两个数字组成。 3.八进制&#xff08;O&#xff09;&am…

Java的类路径究竟是什么?

回答 问了chatgpt这个问题&#xff0c;首先类路径的定义是&#xff1a; 是指一组路径&#xff0c;这些路径告诉Java虚拟机&#xff08;JVM&#xff09;和类加载器在哪里可以找到应用程序所需的类和资源文件。说白了就是在运行java程序的时候需要先将java源代码编译成class文件…

代码随想录——从前序与中序遍历序列构造二叉树(Leetcode105)

题目链接 递归 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

nginx + confd + etcd 实现nginx动态白名单,防止请求host篡改注入攻击

众所周知&#xff0c;浏览器发送到后台请求header中携带的host是可能被修改的&#xff0c;为了防止这件事情发生&#xff0c;就很有必要给后台设置host请求白名单了&#xff0c;本次将介绍nginx如何配置&#xff0c;以及结合confd和etcd实现动态配置。 1. http/https请求的host…

flink cdc mysql整理与总结

文章目录 一、业务中常见的需要数据同步的场景CDC是什么FlinkCDC是什么CDC原理为什么是FlinkCDC业务场景flink cdc对应flink的版本 二、模拟案例1.阿里云flink sql2.开源flink sql(单机模式)flink 安装安装mysql3.flink datastream 三、总结 提示&#xff1a;以下是本篇文章正文…

MFC扩展库BCGControlBar Pro v34.1新版亮点:日历和计划表等功能升级

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v34.1已正式发布了&#xff0c;这个版本包含了对Windows 10/11字体图标的支持、功能区和…

huggingface 笔记:查看GPU占用情况

0 准备部分 0.1 创建虚拟数据 import numpy as npfrom datasets import Datasetseq_len, dataset_size 512, 512 dummy_data {"input_ids": np.random.randint(100, 30000, (dataset_size, seq_len)),"labels": np.random.randint(0, 1, (dataset_size…

PHP+Lucky+Baby母婴用品网站的设计与实现75554-计算机毕业设计项目选题推荐(附源码)

摘 要 近年来&#xff0c;随着移动互联网的快速发展&#xff0c;电子商务越来越受到网民们的欢迎&#xff0c;电子商务对国家经济的发展也起着越来越重要的作用。简单的流程、便捷可靠的支付方式、快捷畅通的物流快递、安全的信息保护都使得电子商务越来越赢得网民们的青睐。现…

中国低调海外巨头,实力超乎想象!

在全球化的浪潮中&#xff0c;中国公司正以前所未有的速度和规模走向世界。他们或许低调&#xff0c;但却实力非凡&#xff0c;在国际市场上掀起了一股不可小觑的“中国风暴”。今天&#xff0c;就让我们揭开那些在国外牛逼到爆炸的中国公司的神秘面纱&#xff0c;深度解析他们…

IP编址、进制转换、IP地址分类、变长子网掩码VLSM、无类域间路由CIDR

前言 网络层位于数据链路层与传输层之间。网络层中包含了许多协议&#xff0c;其中最为重要的协议就是IP协议。网络层提供了IP路由功能。理解IP路由除了要熟悉IP协议的工作机制之外&#xff0c;还必须理解IP编址以及如何合理地使用IP地址来设计网络。 IP编址 每个网段上都有两…

滤波电路应用笔记

滤波器 什么是滤波器&#xff1f; 滤波器是一种使某些频率或频带上的电信号通过而阻止其他信号通过的装置。 滤波电路的作用是尽可能减少脉动直流电压中的交流分量&#xff0c;保持其直流分量&#xff0c;降低输出电压的纹波系数&#xff0c;并使波形相对平滑。整流电路的输出…

商标注册申请名称的概率,多想名称选通过率好的!

近日给深圳客户申请的商标初审下来了&#xff0c;两个类别都下的初审&#xff0c;和当初的判断基本一致&#xff0c;普推知产老杨当时沟通说需要做担保申请注册也可以&#xff0c;后面选择了管家注册&#xff0c;最近大量的帮客户检索商标名称&#xff0c;分享下经验。 两个字基…

PC端应用订阅SDK接入攻略

本文档介绍了联想应用联运sdk接入操作指南&#xff0c;您可在了解文档内容后&#xff0c;自行接入应用联运sdk。 1. 接入前准备 1. 请先与联想商务达成合作意向。 2. 联系联想运营&#xff0c;提供应用和公司信息&#xff0c;并获取商户id、app id、key&#xff08;公私钥、…

【设计模式深度剖析】【4】【结构型】【组合模式】| 以文件系统为例加深理解

&#x1f448;️上一篇:适配器模式 设计模式深度剖析-专栏&#x1f448;️ 目 录 组合模式定义英文原话直译如何理解&#xff1f; 3个角色UML类图代码示例 组合模式的优点组合模式的使用场景示例解析&#xff1a;文件系统 组合模式 组合模式&#xff08;Composite Pattern&a…

【经典论文阅读10】MNS采样——召回双塔模型的最佳拍档

这篇发表于2020 WWW 上的会议论文&#xff0c;提出一种MNS方式的负样本采样方法。众所周知&#xff0c;MF方法难以解决冷启动问题&#xff0c;于是进化出双塔模型&#xff0c;但是以双塔模型为基础的召回模型的好坏十分依赖负样本的选取。为了解决Batch内负样本带来的选择性偏差…