【基于 WebSocket 的多用户网页五子棋】—— 项目结构设计与实用工具类模块

🌈欢迎来到实战项目专栏 ~~ 基于 WebSocket 的多用户网页五子棋

Websocketpp

👀项目结构设计

项目模块划分说明

项目的实现,咱们将其划分为三个大模块来进行:

  • 数据管理模块:基于Mysql数据库进行用户数据的管理
  • 前端界面模块:基于JS实现前端页面(注册,登录,游戏⼤厅,游戏房间)的动态控制以及与服务器的通信
  • 业务处理模块:搭建WebSocket服务器与客户端进行通信,接收请求并进行业务处理

在这⾥回顾⼀下我们要实现的项目功能,我们要实现的是一个在线五子棋对战服务器,提供用户通过浏览器进行用户注册,登录,以及实时匹配,对战,聊天等功能。

而如果要实现这些功能,那么就需要对业务处理模块再次进行细分为多个模块来实现各个功能

业务处理模块的子模块划分:

  • 网络通信模块:基于websocketpp库实现Http&WebSocket服务器的搭建,提供网络通信功能。
  • 会话管理模块:对客户端的连接进行cookie&session管理,实现http短连接时客户端身份识别功能。
  • 在线管理模块:对进入游戏大厅与游戏房间中用户进行管理,提供用户是否在线以及获取用户连接的功能。
  • 房间管理模块:为匹配成功的用户创建对战房间,提供实时的五子棋对战与聊天业务功能。
  • 用户匹配模块:根据天梯分数不同进行不同层次的玩家匹配,为匹配成功的玩家创建房间并加入房间

👀项目流程图

玩家用户角度流程图:

服务器流程结构图:

👀实用工具类模块代码实现

实用工具类模块主要是负责提前实现一些项目中会用到的边缘功能代码,提前实现好了就可以在项目中用到的时候直接使用了

📅日志宏封装

实现程序日志打印:实现一些宏函数,能够辅助我们进行日志信息的打印

cpp 复制代码
[08:29:32-main.cc-22] 文件打开失败
  • time_t time(NULL) :获取系统时间戳
  • struct tm *localtime(time_t * t):将时间戳转化成一个结构体
  • char *strftime(char *buf, int max, char *format, struct tm *tm);:把时间结构体格式化成我们可读的时间字符串
  • int fprintf(FILE *fp,char *format,...) :按照指定格式,把数据写入指定的文件流(FILE )中
cpp 复制代码
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include <time.h>
#include <stdio.h>

#define INF 0 
#define DBG 1 
#define ERR 2 
#define DEFAULT_LOG_LEVEL DBG

#define LOG(level, format, ...) do{\
    if (DEFAULT_LOG_LEVEL > level) break;\
    time_t t = time(NULL);\
    struct tm* tm = localtime(&t);\
    char buf[128];\
    strftime(buf, sizeof(buf), "%H:%M:%S", tm);\
    fprintf(stdout, "[%s - %s:%d]" format "\n", buf, __FILE__, __LINE__, ##__VA_ARGS__);\
}while(0)

#define INF_LOG(format, ...) LOG(INF, format, ##__VA_ARGS__)
#define DBG_LOG(format, ...) LOG(DBG, format, ##__VA_ARGS__)
#define ERR_LOG(format, ...) LOG(ERR, format, ##__VA_ARGS__)

#endif

Mysql-API封装

分别对数据库的连接 &初始化 、句柄的销毁 、语句的执行 进行封装

数据库的连接 &初始化:

  • 初始化句柄
  • 链接服务器
  • 设置字符集
  • 选择数据库
cpp 复制代码
class MySQLUtil
{
public:
    static MYSQL * mysql_create(const std::string & host, 
        const std::string & username, 
        const std::string & password, 
        const std::string & dbname, 
        uint16_t port = 3306)
    {
        //初始化
        MYSQL * conn = mysql_init(nullptr);
        if (!conn) 
        {
            ERR_LOG("mysql_init error");
            return nullptr;
        }
        //链接mysql
        if (!mysql_real_connect(conn,
            host.c_str(), 
            username.c_str(), 
            password.c_str(), 
            dbname.c_str(), 
            port, nullptr, 0))
        {
            ERR_LOG("mysql_real_connect error: %s", mysql_error(conn));
            return nullptr;
        }
        //选择字符集
        if (mysql_set_character_set(conn, "utf8") != 0)
        {
            ERR_LOG("mysql_set_character_set error: %s", mysql_error(conn));
            return nullptr;
        }
        return conn;
    }

    static bool mysql_exec(MYSQL * conn, const std::string & sql)
    {
        if (mysql_query(conn, sql.c_str()))
        {
            ERR_LOG("mysql_query error: %s", mysql_error(conn));
            mysql_destory(conn);
            return false;
        }
        return true;
    }

    static void mysql_destory(MYSQL * conn)
    {
        if (conn != nullptr)
        {
            mysql_close(conn);
        }
        return;
    }
};

Jsoncpp-API封装

封装了两个函数:序列化和反序列化

cpp 复制代码
class JSONUtil
{
public:
    static bool serialize(const Json::Value &root, std::string &str)
    {
        Json::StreamWriterBuilder builder;
        std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
        std::stringstream ss;
        int ret = writer->write(root, &ss);
        if (ret != 0)
        {
            ERR_LOG("json serialize error");
            return false;
        }
        str = ss.str();
        return true;
    }

    static bool deserialize(const std::string &str, Json::Value &root)
    {
        Json::CharReaderBuilder builder;
        std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
        std::string errs;
        bool ret = reader->parse(str.c_str(), str.c_str() + str.size(), &root, &errs);
        if (ret == false)
        {
            ERR_LOG("json deserialize error: %s", errs.c_str());
            return false;
        }
        return true;
    }
};

String-Split封装

实现了字符串分割的功能!

cpp 复制代码
class StringUtil
{
public:
    static int split(const std::string &src, const std::string &sep, std::vector<std::string> &res)
    {
        //123,123,,,123
        size_t pos = 0, idx = 0; //遍历找到分隔符
        while(idx < src.size())
        {
            pos = src.find(sep, idx);
            if (pos == std::string::npos)
            {
                //没有找到分隔符,全部加到结果中
                res.push_back(src.substr(idx));
                return res.size();
            }
            if(pos == idx) //分隔符在开头
            {
                //分隔符在开头
                idx = pos + sep.size();
                continue;
            }
            //找到了分隔符  
            res.push_back(src.substr(idx, pos - idx));
            idx = pos + sep.size();
        }
        return res.size();
    }
};

File-read封装

封装对文件数据的读取功能(对html文件数据进行读取!)

cpp 复制代码
class FileUtil
{
public:
    static bool read(const std::string &filename, std::string &body)
    {
        //以二进制打开文件
        std::ifstream ifs(filename, std::ios::binary);
        if (!ifs.is_open())
        {
            ERR_LOG("open file error: %s", filename.c_str());
            return false;
        }
        //获取文件大小
        size_t fsize = 0;
        ifs.seekg(0, std::ios::end);//把读指针移到文件末尾
        fsize = ifs.tellg(); //获取当前读位置
        ifs.seekg(0, std::ios::beg);//把读指针移到文件开头
        body.resize(fsize);
        //将文件所有数据读取出来
        ifs.read(&body[0], fsize);
        if(ifs.good() == false)
        {
            ERR_LOG("read file error: %s", filename.c_str());
            ifs.close();
            return false;
        }
        ifs.close();
        return true;
    }
};

📢写在最后

接下来登场的是 数据管理模块

相关推荐
QXWZ_IA1 小时前
测绘单位采购RTK:设备价格、账号年费、售后,用时间轴分权重
网络·人工智能·安全
IT大白鼠2 小时前
GitLab 未认证 RCE 应急实战CVE-2026-97229(CVSS 10.0)
网络·安全·gitlab
陈希1232 小时前
Linux 网络诊断工具实战:ping、curl、tcpdump、mtr、dig 用法详解
linux·网络·tcpdump
草莓熊Lotso4 小时前
【C++ 基于微服务的即时通讯系统】文件存储子服务实战:UUID生成、文件IO封装与全接口单元测试
开发语言·网络·数据库·c++·微服务·架构·单元测试
wuyk5556 小时前
Spider-第03讲-HTTP速通与读懂响应
网络·爬虫·网络协议·http
默|笙16 小时前
【Linux网络】网络层协议 IP(1)理解报头、网段划分
linux·网络·tcp/ip
新*21 小时前
从一段 WebSocket 代码聊开:bytes 不是 zlib、binaryType 决定一切,15MB 大消息的零拷贝优化
javascript·python·websocket·性能优化·blob·zlib·arraybuffer
梦到啥说啥1 天前
Linux网络编程:TCP网络协议
网络·网络协议·tcp/ip
Shanks.1 天前
2026 远程控制软件实测:ToDesk / 向日葵 / RustDesk / TeamViewer 在跨城与弱网下的真实差距
网络·远程工作·软件需求