C++集群聊天服务器 数据模块+业务模块+CMake构建项目 笔记 (上)

跟着施磊老师做C++项目,施磊老师_腾讯课堂 (qq.com)

本文在此篇博客的基础上继续实现数据模块和业务模块代码:

C++集群聊天服务器 网络模块+业务模块+CMake构建项目 笔记 (上)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_41987016/article/details/135991635?spm=1001.2014.3001.5501一、mysql 项目数据库和表的设计

myql 项目数据库和表的设计-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_41987016/article/details/135981407?spm=1001.2014.3001.5501二、mysql数据库代码封装

  • include/public.hpp
#ifndef PUBLIC_H
#define PUBLIC_H
/*
    server和client的公共文件
*/
enum EnMsgType {
    LOGIN_MSG = 1, // 登录消息
    LOGIN_MSG_ACK, // 登录响应消息
    REG_MSG, // 注册消息
    REG_MSG_ACK // 注册响应消息
};
#endif // PUBLIC_H
  • include/server/db/db.h
#ifndef DB_H
#define DB_H

#include <mysql/mysql.h>
#include <string>
using namespace std;

// 数据库操作类
class Mysql {
public:
    // 初始化数据库连接
    Mysql();
    // 释放数据库连接资源
    ~Mysql();
    // 连接数据库
    bool connect();
    // 更新操作
    bool update(string sql);
    // 查询操作
    MYSQL_RES *query(string sql);
    // 获取连接
    MYSQL *getConnection();
private:
    MYSQL *m_conn;
};

#endif // DB_H

 src/server/db/db.cpp

#include "db.h"
#include <muduo/base/Logging.h>
// 数据库配置信息
static string server = "127.0.0.1";
static string user = "root";
static string password = "123456";
static string dbname = "chat";

// 初始化数据库连接
Mysql::Mysql() {
    m_conn = mysql_init(nullptr);
    // 这里相当于只是给它开辟了一块存储连接数据的资源空间
}

// 释放数据库连接资源
Mysql::~Mysql() {
    if(m_conn != nullptr) {
        mysql_close(m_conn);
    }
    // 析构的时候把这块资源空间用mysql_close掉
}

// 连接数据库
bool Mysql::connect() {
    MYSQL *p = mysql_real_connect(m_conn,server.c_str(),user.c_str(),
    password.c_str(),dbname.c_str(),3306,nullptr,0);
    if(p!=nullptr) {
        // C和C++代码默认的编码字符是ASCII,如果不设置,
        // 从MYSQL上拉下来的中文显示?
        mysql_query(m_conn, "set names gbk");
        LOG_INFO << "connect mysql success!!!";
    } else{
        LOG_INFO << "connect mysql failed!!!";
    }
    return p;
}

// 更新操作
bool Mysql::update(string sql) {
    if(mysql_query(m_conn, sql.c_str())) {
        LOG_INFO << __FILE__ << ":" << __LINE__ << ":" 
            << sql <<"更新失败!";
        return false;
    }
    return true;
}

// 查询操作
MYSQL_RES* Mysql::query(string sql) {
    if(mysql_query(m_conn, sql.c_str())) {
        LOG_INFO << __FILE__ << ":" << __LINE__ << ":"
            << sql <<"查询失败!";   
        return nullptr;
    }
    return mysql_use_result(m_conn);
}

// 获取连接
MYSQL* Mysql::getConnection() {
    return m_conn;
}

三、Model数据层代码框架设计

  • include/server/user.hpp
#ifndef USER_H
#define USER_H

#include <string>
using namespace std;

// 匹配User表的ORM类
class User {
public:
    User(int id=-1, string name="", string password="", string state="offline") {
        m_id = id;
        m_name = name;
        m_password = password;
        m_state = state;
    }
    void setId(int id) { m_id = id; }
    void setName(string name) { m_name = name; }
    void setPwd(string pwd) { m_password = pwd; }   
    void setState(string state) { m_state = state; }
    
    int getId() const { return m_id; }
    string getName() const { return m_name; }
    string getPwd() const { return m_password; }
    string getState() const { return m_state; }
private:
    int m_id;
    string m_name;
    string m_password;
    string m_state;
};
#endif // USER_H
  • include/server/usermodel.hpp
#ifndef USERMODEL_H
#define USERMODEL_H
#include "user.hpp"
// User表的数据操作类
class UserModel {
public:
    // user表的增加方法
    bool insert(User& user); 
    // 根据用户号码查询用户信息
    User query(int id);
    // 更新用户的状态信息
    bool updateState(User user);
};

#endif // USERMODEL_H
  • src/server/usermodel.cpp
#include "usermodel.hpp"
#include "db.h"
#include <iostream>
// User表的增加方法
bool UserModel::insert(User &user) {
    // 1.组装sql语句
    char sql[1024] = {0};
    std::sprintf(sql,"insert into user(name,password,state) values('%s','%s', '%s')",
         user.getName().c_str(), user.getPwd().c_str(), user.getState().c_str());
    // 2.执行sql语句
    Mysql mysql;
    if(mysql.connect()) {
        if(mysql.update(sql)) {
            // 获取插入成功的用户数据生成的主键id
            user.setId(mysql_insert_id(mysql.getConnection()));
            return true;
        }
    }
    return false;
}

// 根据用户号码查询用户信息
User UserModel::query(int id) {
    // 1.组装sql语句
    char sql[1024] = {0};
    sprintf(sql,"select * from user where id = %d", id);
    // 2.执行sql语句
    Mysql mysql;
    if(mysql.connect()) {
        MYSQL_RES* res = mysql.query(sql);
        if(res != nullptr) {
            MYSQL_ROW row = mysql_fetch_row(res);
            if(row != nullptr) {
                User user;
                user.setId(atoi(row[0]));
                user.setName(row[1]);
                user.setPwd(row[2]);
                user.setState(row[3]);
                // 释放资源
                mysql_free_result(res);
                return user;
            }
        }
    }
    return User();
}

// 更新用户的状态信息
bool UserModel::updateState(User user) {
    // 1.组装sql语句
    char sql[1024] = {0};
    sprintf(sql,"update user set state = '%s' where id = %d",
         user.getState().c_str(), user.getId());
    // 2.执行sql语句
    Mysql mysql;
    if(mysql.connect()) {
        if(mysql.update(sql)) {
            return true;
        }
    }
    return false;
}

四、CMake 构建项目 

  • src/server/CMakeLists.txt
# 定义了一个SRC_LIST变量 包含了该目录下所有的源文件
aux_source_directory(. SRC_LIST)
aux_source_directory(./db DB_LIST)

# 指定生成可执行文件
add_executable(ChatServer ${SRC_LIST} ${DB_LIST})

# 指定可执行文件链接时需要依赖的库文件
target_link_libraries(ChatServer muduo_net muduo_base mysqlclient pthread)
  • src/CMakeLists.txt
add_subdirectory(server)
  • 和src,include,thirdparty同级目录的CMakeLists.txt
cmake_minimum_required(VERSION 3.28.0)
project(chat)

# 配置编译选项
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -g)

# 配置可执行文件生成路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

# 配置头文件搜索路径
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(${PROJECT_SOURCE_DIR}/include/server)
include_directories(${PROJECT_SOURCE_DIR}/include/server/db)
include_directories(${PROJECT_SOURCE_DIR}/thirdparty)

# 加载子目录
add_subdirectory(src)

cmake -B build
cmake --build build

1.测试注册:

telnet 127.0.0.1 6000
{"msgid":3,"name":"heheda","password":"1024"} // 注册

{"msgid":3,"name":"Tom","password":"520"} // 注册

{"msgid":3,"name":"Jerry","password":"1314"} // 注册

2.测试登录:

(1)未登录

(2) 已经登录

telnet 127.0.0.1 6000
{"msgid":1,"id":4,"password":"1024"}

telnet 127.0.0.1 6000
{"msgid":1,"id":4,"password":"1024"}

(3)登录失败

3.gdb排错练习

比如输入以下这句,其实"id":5才对,但是如果误输入的会引起核心中断,如何排查错误呢?

{"msgid":1,"id":"5","password":"520"}

>>gdb调试,比如我们怀疑可能是chatservice.cpp的20行出错了

heheda@linux:~/Linux/Server$ gdb ./bin/ChatServer
(gdb) break chatservice.cpp 20
(gdb) run
telnet 127.0.0.1 6000

输入:

{"msgid":1,"id":"5","password":"520"}

检查出错误了:

reason: [json.exception.type_error.302] type must be number, but is string

故我们把

{"msgid":1,"id":"5","password":"520"}

修改为以下:
​
{"msgid":1,"id":5,"password":"520"}

总结:客户端发送过来一个注册的业务,先从最开始的网络,再通过事件的分发,到业务层的相关的handler处理注册,接着访问底层的model。其中在业务类设计,这里看到的都是对象,方便你把底层的数据模块改成你想要的,例如mysql,sql,oracle,mongoDB等都行。实现了网络模块,业务模块以及数据模块的低耦合。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NFTScan 与 Merlin Protocol 共同推出 BRC20 Indexer Oracle,于今日正式上线!

近日&#xff0c;NFT 数据基础设施 NFTScan 与 Merlin Protocol 进行战略合作&#xff0c;联合推出了比特币网络原生资产 Indexer Oracle 服务&#xff0c;现在该服务已在 NFTScan 开发者平台上线&#xff0c;任何开发者都可以注册使用&#xff01; Merlin Protocol 是一个专用…

【学习笔记】详解换根法(换根DP)

一.换根DP的概念 1.换根DP是什么&#xff1f; 换根DP&#xff0c;又叫二次扫描&#xff0c;是树形DP的一种。 2.换根DP能解决什么问题&#xff1f; 换根DP能解决不指定根结点&#xff0c;并且根节点的变化会对一些值产生影响的问题。例如子结点深度和、点权和等。如果要 暴力…

使用JDBC连接mysql

JDBC:Java DataBase Connectivity,Java数据库连接。 使用Java语言操作关系型数据库的一套API。 原理&#xff1a;官方&#xff08;sun公司&#xff09;定义出一套操作所有关系型数据库的规则&#xff0c;即接口&#xff1b;所有的数据库厂商去实现这套接口&#xff0c;提供数据…

[word] word小数点对齐怎么设置 #微信#其他#其他

word小数点对齐怎么设置 使用Word编辑文档的时候&#xff0c;如果有小技巧的话&#xff0c;可以解决很多遇到的问题&#xff0c;也让工作更高效的完成&#xff0c;下面给大家分享word小数点对齐怎么设置的小技巧。 1、设置格式 选中内容&#xff0c;点击段落一一制表符&#…

2024.2.3 寒假训练记录(17)

补一下牛客&#xff0c;菜得发昏了&#xff0c;F搞了两个小时都没搞出来&#xff0c;不如去开H了 还没补完 剩下的打了atc再来 文章目录 牛客 寒假集训1A DFS搜索牛客 寒假集训1B 关鸡牛客 寒假集训1C 按闹分配牛客 寒假集训1D 数组成鸡牛客 寒假集训1E 本题又主要考察了贪心牛…

react 使用react-seamless-scroll实现无缝滚动

文章目录 1. 实现无缝滚动效果2. react-seamless-scroll 无缝滚动案例介绍3. react 项目集成3.1 项目引入 cssSeamlessScroll 滚动组件3.2 完整代码3.2.1 newBet.tsx 代码3.2.2 index.module.scss 1. 实现无缝滚动效果 实现单步向下滚动点击更多展开&#xff0c;收起&#xff0…

Python爬虫urllib详解

前言 学习爬虫&#xff0c;最初的操作便是模拟浏览器向服务器发出请求&#xff0c;那么我们需要从哪个地方做起呢&#xff1f;请求需要我们自己来构造吗&#xff1f;需要关心请求这个数据结构的实现吗&#xff1f;需要了解 HTTP、TCP、IP 层的网络传输通信吗&#xff1f;需要知…

Java八大常用排序算法

1冒泡排序 对于冒泡排序相信我们都比较熟悉了&#xff0c;其核心思想就是相邻元素两两比较&#xff0c;把较大的元素放到后面&#xff0c;在一轮比较完成之后&#xff0c;最大的元素就位于最后一个位置了&#xff0c;就好像是气泡&#xff0c;慢慢的浮出了水面一样 Jave 实现 …

RabbitMQ_00000

MQ的相关概念 RabbitMQ官网地址&#xff1a;https://www.rabbitmq.com RabbitMQ API地址&#xff1a;https://rabbitmq.github.io/rabbitmq-java-client/api/current/ 什么是MQ&#xff1f; MQ(message queue)本质是个队列&#xff0c;FIFO先入先出&#xff0c;只不过队列中…

Jmeter 基于Docker 实现分布式测试

基于Docker 实现分布式测试 制作Jmeter基础镜像制作工作节点镜像启动工作节点启动控制节点遇到的问题 使用Docker 部署Jmeter非常方便&#xff0c;可以省略软件的安装以及配置&#xff0c;比如jdk、jmeter。需要部署多个工作节点可以节省时间。 制作Jmeter基础镜像 下载jmeter…

Kubernetes集群搭建

一、概述 Kubernetes是一个Google开源的全新的分布式容器集群管理系统&#xff0c;由于从第一个字母到字母s中间有8个字母&#xff0c;所以简称K8s。 二、准备 ip角色内存192.168.187.130master4G192.168.187.131node2G192.168.187.132node2G 小提示&#xff1a; 设置静态i…

【课程作业_01】国科大2023模式识别与机器学习实践作业

国科大2023模式识别与机器学习实践作业 作业内容 从四类方法中选三类方法&#xff0c;从选定的每类方法中 &#xff0c;各选一种具体的方法&#xff0c;从给定的数据集中选一 个数据集&#xff08;MNIST&#xff0c;CIFAR-10&#xff0c;电信用户流失数据集 &#xff09;对这…

TCP TIME_WAIT 过多怎么处理

文章目录 1.什么是 TCP TIME_WAIT&#xff1f;2.为什么要 TIME_WAIT?3.TIME_WAIT 过多的影响4.解决办法4.1 调整短连接为长连接4.2 调整系统内核参数 5.小结参考文献 1.什么是 TCP TIME_WAIT&#xff1f; TCP 断开连接四次挥手过程中&#xff0c;主动断开连接的一方&#xff…

ctfshow——文件包含

文章目录 web 78——php伪协议第一种方法——php://input第二种方法——data://text/plain第三种方法——远程包含&#xff08;http://协议&#xff09; web 78——str_replace过滤字符php第一种方法——远程包含&#xff08;http://协议&#xff09;第二种方法——data://&…

游戏被DDOS攻击无法访问时该如何处理

游戏行业随着时代的发展有着突飞猛进的变化&#xff0c;尤其是互联网时代智能手机的普及&#xff0c;让游戏行业发展上了一个新的台阶。因为游戏带来的巨大利润&#xff0c;游戏行业一直是DDoS攻击的首选目标。 DDoS是Distributed Denial of Service的缩写&#xff0c;即分布式…

学习Android的第二天

目录 Android User Interface 用户界面 UI Android View与ViewGroup的概念 Android View android.view.View android.view.View XML 属性 android:id 属性 Android ViewGroup android.view.ViewGroup ViewGroup.LayoutParams ViewGroup.MarginLayoutParams ViewGr…

Redis核心技术与实战【学习笔记】 - 19.Pika:基于SSD实现大容量“Redis”

前言 随着业务数据的增加&#xff08;比如电商业务中&#xff0c;随着用户规模和商品数量的增加&#xff09;&#xff0c;就需要 Redis 能保存更多的数据。你可能会想到使用 Redis 切片集群&#xff0c;把数据分散保存到不同的实例上。但是这样做的话&#xff0c;如果要保存的…

java社区养老年人服务系统springboot+vue

为了帮助用户更好的了解和理解程序的开发流程与相关内容&#xff0c;本文将通过六个章节进行内容阐述。 第一章&#xff1a;描述了程序的开发背景&#xff0c;程序运用于现实生活的目的与意义&#xff0c;以及程序文档的结构安排信息&#xff1b; 第二章&#xff1a;描述了程序…

uniapp 高德地图显示

1. uniapp 高德地图显示 使用前需到**高德开放平台&#xff08;https://lbs.amap.com/&#xff09;**创建应用并申请Key   登录 高德开放平台&#xff0c;进入“控制台”&#xff0c;如果没有注册账号请先根据页面提示注册账号   打开 “应用管理” -> “我的应用”页面…

Leetcode 85. 最大矩形

题目信息 LeetoCode地址: 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目理解 该题是84题的升级版。84题给出了一个一维数组&#xff0c;即一行数据&#xff0c;每个元素是高度。而该题则是给出了二维数组&#xff0c;只需我们将每一行的高度…