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)) {// 获取插入成功的用户数据生成的主键iduser.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等都行。实现了网络模块,业务模块以及数据模块的低耦合。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Autonomous_Exploration_Development_Environment的PathFollower学习笔记

1.PathFollow算法简介&#xff1a; PathFollow算法是路径跟踪算法&#xff0c;是在得到由localplanner算法发布的无碰撞路径话题”/path”中的路径数据start_path(相对于车体坐标系的一系列路径点(101个点))&#xff0c;根据车体与目标之间的角度和距离&#xff0c;控制车辆的…

Ubuntu18.04安装Matlab流程笔记

提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 Ubuntu18.04 安装Matlab流程 下载安装包和破解文件安装Matlab注册并运行 下载安装包和破解文件 matlabR2019A源码 提取码:2ztb 下载的Linux matlab2018a文件夹内有三个文件&#xff1a; # 解压Matlab201…

【unity小技巧】unity3d环境带雾的昼夜系统变化

最终效果 文章目录 最终效果眩光素材眩光配置全局灯光配置天空盒配置天空盒资产配置天空盒&#xff0c;开启雾 代码控制天空盒 环境 雾 灯光昼夜交替变化参考完结 眩光素材 链接&#xff1a;https://pan.baidu.com/s/1qlFSJSju6ZjwCylwkh14eA?pwdveww 提取码&#xff1a;veww…

了解 Redis Channel:消息传递机制、发布与订阅,以及打造简易聊天室的实战应用。

文章目录 1. Redis Channel 是什么2. Redis-Cli 中演示使用3. 利用 Channel 打造一个简易的聊天室参考文献 1. Redis Channel 是什么 Redis Channel 是一种消息传递机制&#xff0c;允许发布者向特定频道发布消息&#xff0c;而订阅者则通过订阅频道实时接收消息。 Redis Cha…

N-142基于springboot,vue停车场管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 项目采用前后端分离 前端技术&#xff1a;vueelementUI 服务端技术&#xff1a;springbootmybatis-plus 本项目分为普通用户和管理员…

OceanBase 4.2.2 GA 发布,全新特性快速预览!

在 2023 年度发布会上&#xff0c;OceanBase 沿着“一体化”产品战略思路&#xff0c;发布了一体化数据库的首个长期支持版本 4.2.1 LTS。作为 4.0 系列的首个 LTS 版本&#xff0c;该版本的定位是支撑客户关键业务稳定长久运行&#xff0c;我们非常认真的打磨了这个版本&#…

深入理解网络编程之BIO和NIO

目录 原生JDK网络编程BIO BIO通信模型服务端代码 BIO通信模型客户端代码 伪异步模型服务端代码&#xff08;客户端跟之前一致&#xff09; 原生JDK网络编程NIO 什么是NIO&#xff1f; NIO和BIO的主要区别 阻塞与非阻塞IO NIO之Reactor模式 NIO中Reactor模式的基本组成…

数据分析基础之《pandas(4)—pandas画图》

1、DataFrame.plot(xNone, yNone, kindline) 说明&#xff1a; x&#xff1a;设置x轴标签 y&#xff1a;设置y轴标签 kind&#xff1a; line 折线图 bar 柱状图 hist 直方图 pie 饼图 scatter 散点图 # 找到p_change和turnover之间的关系 data.plot(xvolume, yturnover, kinds…

手把手教你开发Python桌面应用-PyQt6图书管理系统-主界面UI设计实现

锋哥原创的PyQt6图书管理系统视频教程&#xff1a; PyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~_哔哩哔哩_bilibiliPyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~共计24条视频&…

随着网络的快速发展,网络安全问题也日益凸显,遇到攻击该如何处理,如何抉择合适的防护方案

DexunCloud 经过研究发现当今世界&#xff0c;随着网络的快速发展&#xff0c;网络安全问题也日益凸显。其中&#xff0c;DDoS&#xff08;分布式拒绝服务&#xff09;攻击被认为是网络安全领域里最为严重的威胁之一。毫无疑问&#xff0c;DDoS攻击不仅可以导致网络服务中断&am…

2024 高级前端面试题之 HTTP模块 「精选篇」

该内容主要整理关于 HTTP模块 的相关面试题&#xff0c;其他内容面试题请移步至 「最新最全的前端面试题集锦」 查看。 HTTP模块精选篇 1. HTTP 报文的组成部分2. 常见状态码3. 从输入URL到呈现页面过程3.1 简洁3.2 详细 4. TCP、UDP相关5. HTTP2相关6. https相关7. WebSocket的…

【数据结构】单向链表实现 超详细

目录 一. 单链表的实现 1.准备工作及其注意事项 1.1 先创建三个文件 1.2 注意事项&#xff1a;帮助高效记忆和理解 2.链表的基本功能接口 2.0 创建一个 链表 2.1 链表的打印 3.链表的创建新节点接口 4.链表的节点插入功能接口 4.1 尾插接口 4.2 头插接口 4.3 指定位…