在线五子棋对战

"你经过我每个灿烂时刻,我才真正学会如你般自由~" 


项目介绍:

(1) 项目简介

        本项目是一款网页版的五子棋对战游戏,其主要支持以下几种功能:

● ⽤⼾管理: 实现⽤⼾注册, ⽤⼾登录、获取⽤⼾信息、⽤⼾天梯分数记录、⽤⼾比赛场次记录等.

● 匹配对战: 实现两个玩家在⽹⻚端根据天梯分数匹配游戏对⼿,并进⾏五⼦棋游戏对战的功能.

● 聊天功能: 实现两个玩家在下棋的同时可以进⾏实时聊天的功能.

(2) 核心技术

        ● HTTP/WebSocket/Websocket++  ● JsonCpp  ● Mysql  ● C++11 ● HTML/CSS/JS/AJAX

(3) 环境搭建(Centos-7.6)

① 安装wget⼯具

# root:
yum install wget

② 更换软件源

# 进入到该目录
cd /etc/yum.repos.d
# 配置 yum源 
sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo
# 安装SCL软件源
sudo yum install centos-release-scl-rh centos-release-scl
# 安装epel软件源
sudo yum -y install epel-release

③ 安装其他工具

# 安装lrzsz传输⼯具
sudo yum install lrzsz -y

# 安装⾼版本gcc/g++编译器
sudo yum install devtoolset-8-gcc devtoolset-8-gcc-c++ -y
// 设置开机 时自动启用
echo "source /opt/rh/devtoolset-7/enable" >> ~/.bashrc
// "~" 表示的是当前用户的主目录
source ~/.bashrc

# 安装gdb调试器
sudo yum install gdb -y

# 安装git
sudo yum install git -y

# 安装cmake
sudo yum install cmake

# 安装boost库
sudo yum install boost-devel.x86_64 -y

# 安装Jsoncpp库
sudo yum install jsoncpp-devel -y

④ 安装Mysql数据库服务及开发包

# 获取mysql官⽅yum源
wget http://repo.mysql.com/mysql57-community-release-el7-10.noarch.rpm
# 安装mysql官⽅yum源
sudo rpm -ivh mysql57-community-release-el7-10.noarch.rpm
# 安装Mysql数据库服务
sudo install -y mysql-community-server
# 安装Mysql开发包
sudo yum install -y mysql-community-devel

# 启动Mysql
systemctl start mysqld.service
# 设置开机项
systemctl enable mysqld.service
# 停止服务
service mysqld stop
过期Key:
        如果因为GPG KEY的过期导致安装失败:
rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
查看临时密码:

        首次登录时,会在MySQL里的日志文件中生成一个临时密码:

# 也可以使用这个命令直接获取
sudo grep 'temporary password' /var/log/mysqld.log

# 查看mysql 密码策略
show variables like 'validate_password%';

# 设置密码强度
set global validate_password_policy = 0 (密码强度)
# 设置密码长度
set global validate_password_length = 1 (长度)
# 修改密码 才能进行后面的操作
alter user 'root'@'%' Identified by 'XXXXXXX';

        如果你已经忘记密码了,你可以进入 /etc/my.cnf文件中设置:

[mysqld]: skip-grant-tables
配置Mysql文件:

● 配置 '/etc/my.cnf' 字符集        

[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
character-set-server=utf8

        

⑤ 安装Websocketpp库

# 远方拉取库
git clone https://github.com/zaphoyd/websocketpp.git

# 进入websocketpp目录
cd /websocketpp mkdir build
# 在build目录下: 
cmake -DCMAKE_INSTALL_PREFIEX=/usr ../
# 生成临时文件都会放在 makefile文件

# 安装websocketpp
sudo make install 

验证是否安装成功:

进入/websocketpp/examples       

        关于什么是WebSocket可以看看这篇文章:

我们来谈谈websocket_websocket 线程_RNGWGzZs的博客-CSDN博客                


前置工具包:

        该项目牵涉到数据库的常用操作,数据序列化反序列化,文件读写等操作,所以我们先对这些操作进行一个封装,方便之后接口的调用。

mysql:

        其中包含了创建初始化 mysql连接句柄,以及sql语句的执行和句柄销毁。

class mysql_util
    {
    public:
        // 用创建句柄+初始化+连接
        static MYSQL *mysql_create(
            const std::string host,
            const std::string username,
            const std::string password,
            const std::string db_name,
            uint16_t port = 3306)
        {
            // 初始化
            MYSQL *mysql = mysql_init(nullptr);
            if (mysql == nullptr)
            {
                ERR_LOG("mysql init failed");
                return nullptr;
            }

            // 库连接
            if (mysql_real_connect(mysql, host.c_str(), username.c_str(), password.c_str(), db_name.c_str(), port, nullptr, 0) == nullptr)
            {
                ERR_LOG("mysql connect server failed:%s", mysql_error(mysql));
                mysql_close(mysql);
                return nullptr;
            }

            // 设置字符集
            if (mysql_set_character_set(mysql, "utf8") != 0)
            {
                ERR_LOG("mysql charset failed:%s", mysql_error(mysql));
                mysql_close(mysql);
                return nullptr;
            }
            return mysql;
        }

        // 执行sql
        static bool mysql_exec(MYSQL *mysql, const std::string &sql)
        {
            int ret = mysql_query(mysql, sql.c_str());
            if (ret != 0)
            {
                ERR_LOG("SQL:%s ERROR:%s", sql.c_str(), mysql_error(mysql));
                return false;
            }
            return true;
        }

        // 销毁句柄释放资源
        static void mysql_release(MYSQL *mysql)
        {
            if (mysql == nullptr)
                return;
            mysql_close(mysql);
        }
    };

Json工具:

        包含传输数据的序列化和反序列化过程。

class json_util
    {
    public:
        static bool serialize(const Json::Value &value, std::string &res)
        {
            Json::StreamWriterBuilder swb;
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());

            std::stringstream ss;
            int ret = sw->write(value, &ss);
            if (ret != 0)
            {
                ERR_LOG("json serialization faild!");
                return false;
            }

            res = ss.str();
            return true;
        }

        static bool unserialize(const std::string &str, Json::Value &value)
        {
            Json::CharReaderBuilder crb;
            std::unique_ptr<Json::CharReader> cb(crb.newCharReader());

            bool ret = cb->parse(str.c_str(), str.c_str() + str.size(), &value, nullptr);
            if (ret == false)
            {
                ERR_LOG("json unserialize failed!");
                return false;
            }
            return true;
        }
    };

字符串分割\读文件:

  class string_util
    {
    public:
        static int split(const std::string &in, const std::string &sep, std::vector<std::string> &arry)
        {
            arry.clear();
            // idx:表示切分字符串的位置
            size_t idx = 0;
            while (idx < in.size())
            {
                size_t pos = in.find(sep, idx);
                if (pos == std::string::npos)
                {
                    // 虽然原字符串没有sep 但 pos-in != 0
                    arry.push_back(in.substr(idx));
                    break;
                }
                
                // "出现多个相连sep: 33,,,,"
                if (pos == idx) {
                    idx += sep.size();
                    continue;
                }
                res.push_back(src.substr(idx, pos - idx));
                idx = pos + sep.size();
            }
            return arry.size();
        }
    };

    class file_util
    {
    public:
        static bool read_file(const std::string filename, std::string &body)
        {
            std::fstream fs(filename, std::ios::in | std::ios::binary);
            if (!fs.is_open())
            {
                ERR_LOG("file open faild:%s", filename.c_str());
                return false;
            }

            // 使用偏移量的方法 读取整个文件
            // seekg:设置读取偏移指针的位置
            // tellg:返回当前position
            fs.seekg(0, std::ios::end);
            body.resize(fs.tellg());
            fs.seekg(std::ios::beg); // 回到文件开头
            fs.read(&body[0], body.size());
            // good:Check whether state of stream is good
            if (fs.good() == false)
            {
                ERR_LOG("read file content faild:%s", filename.c_str());
                fs.close();
                return false;
            }

            fs.close();
            return true;
        }
    };

功能模块:

用户管理模块: 

        用户管理模块中,我们需要为玩家存储他们的各项身份信息,比如:id,玩家名,天梯分数,总场数,胜场数……这些数据都是存储在磁盘上的,由强大的Mysql进行管理。

        另外,为了取得这些数据,我们实现一个类来完成,user_table类就是为了获取数据库中的数据的。

        

在线⽤⼾管理模块:        

        在线⽤⼾管理,是对于当前游戏⼤厅和游戏房间中的⽤⼾进⾏管理。它需要承担对在线用户以及正在进行五子棋对战的玩家进行管理。并通过一定的策略对玩家进行 "保活" 查询。

                

游戏房间管理:        

         这是该项目功能的主逻辑。游戏房间模块是在两个玩家成功匹配后生成的。该房间需要支持游戏玩法和实时聊天的功能。

Session管理:

什么是session?

        http是一种无状态的短连接协议。所谓无状态,就是不知道这条信息或者这份数据是谁发送的。我们可以试想一下,两个正在进行游戏的玩家,会在一张棋盘上落子,客户端点击发送黑白棋子,但在计算机看无非就是一串01序列,压根不知道这条消息是属于谁的。

        由此,服务器为每个⽤⼾浏览器创建⼀个会话对象(session),在需要保存⽤⼾数据时,服务器程序可以把⽤⼾数据写到⽤⼾浏览器独占的session中,当⽤⼾使⽤浏览器访问该程序时,就会携带这个sessio信息,该程序可以从⽤⼾的session中读取该⽤⼾的历史数据,识别该连接对应的⽤⼾,并为⽤⼾提供服务。        

         在这里我们需要设计一个session类,并且这个session类不能一直存在,当用户结束对局或者用户下线等,该session对象就需要被清理掉。

匹配队列实现:

        五⼦棋对战的玩家匹配是根据⾃⼰的天梯分数进⾏匹配的,实现玩家匹配的思想⾮常简单,为不同的档次设计各⾃的匹配队列,当⼀个队列中的玩家数量⼤于 等于2的时候,则意味着同⼀档次中,有2个及以上的⼈要进⾏实战匹配,则出队队列中的前两个⽤⼾,并为之创建游戏房间准备对战。

        剩余的模块属于前端知识,诸如登录页面、注册页面、游戏大厅等等,也就不过多赘述了。


项目实现:

日志打印:

#ifndef __MY_LOG__
#define __MY_LOG__
#include <iostream>
#include <stdio.h>
#include <time.h>
#include <pth
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值