C++项目:在线五子棋对战(网页版)

news2024/11/13 15:11:30

项目介绍

本项⽬主要实现⼀个⽹⻚版的五⼦棋对战游戏,其主要⽀持以下核⼼功能:

• 用户管理:实现用户注册,用户登录、获取用户信息、用户天梯分数记录、用户比赛场次记录等。
• 匹配对战:实现两个玩家在网页端根据天梯分数匹配游戏对⼿,并进行五子棋游戏对战的功能。
• 聊天功能:实现两个玩家在下棋的同时可以进⾏实时聊天的功能。

程序截图

开发环境

• Linux (Centos-7.6)

• VSCode/Vim
• g++/gdb
• Makefile

核心技术

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

项目大流程

• 环境搭建(在Linux环境下安装需要用到的的工具以及第三方库)

• 框架设计

• 前置知识的了解

• 模块开发

配置开发环境

项目框架

项目期望:用户访问服务器获取注册页面,通过注册页面注册账号,注册成功后在登录页面进行登录。登录成功后进入游戏大厅,在游戏大厅中进行匹配对战,匹配成功,将进入游戏房间内与对手进行实时对战和实时聊天。

用户访问服务器获取的注册页面、登录页面、游戏大厅页面和游戏房间页面,属于静态资源请求。进行注册请求、登录请求、进入游戏大厅后展示个人信息的个人信息请求、匹配对战请求和下棋聊天请求属于动态功能请求。

服务器流程图:

模块解析

在项目中,需要用到6个模块,分别是:

数据管理模块:基于mysql数据库进行数据管理以及封装数据管理模块实现数据库访问。

在数据管理模块中,需要实现的功能有:注册新用户功能、登录验证功能、通过用户名获取用户信息功能、通过用户id获取用户信息功能,以及对战胜利和失败后,对数据的更新功能。

网络服务器模块:基于websocketpp库搭建websocket服务器,实现与客户端网络通信。

早网络服务器模块中,websocketpp支持http协议和websocket协议,需要实现的是http请求处理回调函数和websocket请求处理回调函数。其中,HTTP请求的处理回调函数包含了静态资源请求处理、用户注册请求处理、用户登录请求处理和用户信息请求处理。websocket请求处理回调函数包含游戏大厅、游戏房间等长连接的请求处理。

session管理模块:封装session管理,实现http客户端通信状态的维护及身份识别。

session管理模块是用于在浏览器中保存用户的通信状态和身份识别的,当用户在注册或登录后,进入了游戏大厅或游戏房间,那么将会永久保存其Cookie,当用户断开连接后,在一定的时间内,他的Cookie就会被销毁,在登录时需要重新输入账号密码。

在线用户管理模块:对于进入游戏大厅&游戏房间的长连接通信进行管理,实现随时能够获取客户端连接进行消息的主动推送。

在线用户管理模块的作用是将用户id与游戏大厅或游戏房间连接起来,在建立了websocket长连接后,将玩家加入到游戏大厅或游戏房间。当游戏结束,将玩家从游戏房间移除,当玩家退出客户端后,websocket连接断开,将玩家从游戏大厅移除。除此之外,还需要实现判断用户是否在线,即在游戏大厅中或游戏房间中,还需要通过玩家用户id去获取游戏大厅/游戏房间管理对应的通信连接。

游戏房间管理:对于同一个房间中的用户及动作进行处理(对战匹配,下棋,聊天,退出)。

在游戏房间中,游戏房间包含了房间id,玩家数量,房间状态、黑棋白棋玩家的id,以及棋盘,在线用户管理和数据模块管理的指针等字段。在游戏房间中,需要实现的是下棋的动作、处理下棋动作、处理聊天动作和处理玩家退出房间的动作,以及将动作处理广播给房间的所有玩家的方法。

游戏房间管理是需要实现的是对房间的管理,因此需要一个房间的计数器、需要实现的是创建一个游戏房间,通过房间id获取房间信息,通过用户id获取所在的房间的信息,删除房间等方法。

对战匹配管理:将所有玩家根据分数进行等级划分,进行不同等级的对战匹配。

匹配对战分有三个段位:普通、高手和大神三种段位,分别使用三个匹配队列进行玩家的匹配队列的进入等待,并且使用三个线程,异步高效地处理三种玩家的匹配对战。

对于匹配队列来说,不是使用队列,而是使用双向链表来作为匹配队列。匹配队列需要的功能是:出队入队、阻塞线程、移除指定元素等功能。

对于匹配队列的管理,需要实现将玩家进行入队,出队等操作。

将6个模块整合起来,在服务器中进行业务处理:通过网络通信获取到客户端的请求,提供不同的业务处理。

前置知识的学习:

1.websocketpp的学习和使用。

本项目中,使用websocketpp来搭建服务器,因为websocketpp同时支持http和websocket。在本项目中,HTTP用于注册、登录等服务请求中提供短链接服务。而websocket用于在游戏大厅或游戏房间中,提供长连接,并且服务器主动发送消息给客户端的服务。下面链接是关于websocket的介绍以及使用websocketpp搭建简单服务器的框架:

websocket协议

我在做项目时的难点:①HTTP请求响应和websocket请求响应的区别。②服务器搭建流程。③为什么连接句柄是使用lib::weak_ptr管理起来,而不是使用lib::shared_ptr来管理。

解决:

①TTP请求响应和websocket请求响应的区别:

HTTP请求回调处理函数主要是处理来自客户端的HTTP请求,它从连接对象中获取HTTP请求的正文,并通过请求对象获取URI和方法等信息,然后根据不同的方法和URI来进行相应的处理,最后构建HTTP响应对象并发送回客户端。HTTP是一种无状态协议,每个请求都是独立的。

WebSocket消息处理回调函数主要是处理来自客户端的WebSocket消息,它从连接对象中获取WebSocket消息的内容,并进行相应的处理逻辑。不像HTTP请求那样需要获取URI和方法等信息,WebSocket是一种双向通信协议,服务器和客户端可以在持久连接上进行实时双向通信。这个回调函数通过使用连接对象的 send 方法直接将响应消息发送回客户端。

服务器搭建流程:先实例化出websocketpp的server类对象,通过server类对象设置日志等级、调度器、四种处理回调函数、进入监听状态、获取客户端新连接,最后启动服务器。

③为什么连接句柄是使用lib::weak_ptr管理起来,而不是使用lib::shared_ptr来管理。

hdl是wssrv.start_accept()创建出来的连接对象的引用,他们两者会有互相引用的关系,如果使用了lib::weak_ptr来管理hdl,就不会发生内存泄漏。

MySQLClient库

JsonCpp

模块开发

数据库代码

数据库设计这边,玩家的信息包含了玩家的用户id、用户名、用户密码、天梯分数、排位总场次和胜场总场次。其中,用户id作为主键,并且是自增长的,而用户名和用户密码不能为空,且用户名唯一。根据这个需求,写出以下代码:

drop database if exists online_gobang;
create database if not exists online_gobang;
use online_gobang;
create table if not exists user(
    id int primary key auto_increment comment '用户id',
    username varchar(32) unique key not null comment '用户名',
    password varchar(128) not null comment '用户密码',
    score int comment '分数',
    total_count int comment '总场次',
    win_count int comment '胜利场次'
);

日志打印

#ifndef _M_LOGGER_H_
#define _M_LOGGER_H_
#include<stdio.h>
#include<time.h>

//正常
#define INF 0
//调试信息
#define DBG 1
//错误信息
#define ERR 2

//strftime:将时间转换为指定格式的字符串
#define LOG(level,format,...) do{\
    time_t t = time(NULL);\
    struct tm *lt = localtime(&t);\
    char buf[32];\
    strftime(buf,21,"%H:%M:%S",lt);\
    fprintf(stdout,"[%s %s:%d] " format "\n",buf,__FILE__,__LINE__,##__VA_ARGS__);\
}while(0)

#define ILOG(format,...) LOG(INF,format,##__VA_ARGS__);
#define DLOG(format,...) LOG(DBG,format,##__VA_ARGS__);
#define ELOG(format,...) LOG(ERR,format,##__VA_ARGS__);

工具类模块开发

工具类模块开发代码

数据管理模块开发

数据管理模块开发代码

在测试代码的时候,发现插入的数据长度太长,也就是密码在被加密之后,长度超过了我原本设置的password varchar(32)。因此,我需要将其改成varchar(128),并且重新导入:

[wjmhlh@VM-12-9-centos myspace]$ mysql -uroot -p < online_gobang.sql   --重新导入
Enter password: 
[wjmhlh@VM-12-9-centos myspace]$ mysql -uroot -p
Enter password: 


Database changed
mysql> desc user;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int(11)      | NO   | PRI | NULL    | auto_increment |
| username    | varchar(32)  | NO   | UNI | NULL    |                |
| password    | varchar(128) | NO   |     | NULL    |                |
| score       | int(11)      | YES  |     | NULL    |                |
| total_count | int(11)      | YES  |     | NULL    |                |
| win_count   | int(11)      | YES  |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)


mysql> select * from user;
+----+----------+-------------------------------------------+-------+-------------+-----------+
| id | username | password                                  | score | total_count | win_count |
+----+----------+-------------------------------------------+-------+-------------+-----------+
|  1 | xiaoming | *E56A114692FE0DE073F9A1DD68A00EEB9703F3F1 |  1000 |           0 |         0 |
+----+----------+-------------------------------------------+-------+-------------+-----------+
1 row in set (0.00 sec)

在线用户管理模块开发

在线用户管理模块开发代码

在实现代码中,需要注意的是,当websocket的长连接断开后,我在移除游戏大厅或游戏房间的在线用户管理的uid时,而由于是使用unordered_map作为容器,因此与之对应的通信连接conn就会失去一个映射关系,而通信连接使用了uinque_ptr进行管理,计数器直接减为0,这个通信连接就会自动销毁。

房间管理模块开发

房间管理模块开发代码

session管理模块开发

session管理模块开发

游戏对战匹配模块开发

匹配对战模块开发代码

服务器网络通信模块开发

服务器网络通信模块开发​​​​​​​

项目总结

1. 为什么做这个项目

为什么做这个C++五子棋对战网页版的项目,我总结了三点:

①我学习了网络编程,比如HTTP、socket编程等,还没有通过项目实践过,开发经验不足,因此我需要做一个关于网络通信连接的项目来加深我对网络编程的理解和使用。

②我是学习C++的一名计算机专业的学生,对自己掌握的C++的程度,需要有项目的实践操作去检验自己的学习成果。

③在之前学习计算机技术,实践都是通过从一些做题网站中,去做题目来检验自己对知识的掌握,以及写代码的能力,但是却没有过去写一个项目来检验自己的代码逻辑和写代码的能力的,而这个项目的开发,能够很好地检验我自己的代码逻辑和写代码的能力。


2. 项目中都用到了那些技术

在项目中,主要运用到了websocket协议和HTTP协议,以及C++11中的一些新特性,比如包装器,bing方法,互斥锁、智能指针等等,还有就是使用到了STL,比如vector、list、unordered_map等,以及是g++/gcc,makefile,vim/vscode等。


3. 讲一下项目都有那些功能,大概是怎么实现的

在线五子棋对战网页版,主要的功能有:让用户通过浏览器访问服务器,从而实现用户注册,用户登录,对战匹配,实时对战和实时聊天功能。

实现的大概思路是:

实现了6个模块,第一个模块是数据管理模块,这个模块是基于MySQL数据库进行数据管理,并且封装了MySQL的C语言接口,来进行数据管理。第二个模块是在线用户管理模块,这个模块对于进入了的游戏大厅和游戏房间的长连接通信进行管理,通过用户的uid与相对于的客户端的通信连接建立起映射关系,服务器可以实现随时获取客户端通信连接进行消息的主动推送。第三个模块是房间管理模块,在这个模块里面,先是实现了房间类,在房间类中,实现了下棋、聊天等动作,而再实现了一个房间管理的类,通过房间的管理,可以进行房间的创建、销毁、通过用户的id获取房间信息,通过房间id获取房间信息等功能。第四个模块是session模块,这个模块封装了session的管理,实现了HTTP通信连接中客户端通信状态的维护和登录或进入游戏大厅或游戏房间时进行身份识别。第五个模块是游戏对战匹配模块,在这个模块里面是将所有玩家根据分数吗,进行了档次的划分,使用多线程,分别对同档次的玩家进行不同的对战匹配。第六个模块是网络服务器的模块开发,在这个模块里面,是基于了websocketpp来搭建了服务器,实现了与客户端进行通信的功能。


4. 做的时候遇到过什么问题,当时是怎么想的,最后是怎么解决的

在做项目的过程中,遇到了不少的技术问题。

①比如在使用websocketpp协议的时候,一开始的时候没有掌握好HTTP协议和websocket协议的使用,比如说在接受请求和发送响应,它们是有区别的。一开始以为在响应的时候,需要获取uri和方法,然后根据uri和方法将那些响应的。然后当时在网上查了文档,别人写的文章,还问了一些类似chargpt的ai,最后才发现,原来websocket不需要获取请求中的uri,可以直接通过send方法给客户端做出响应。

②一开始在设计user表的时候,我把密码的长度设置了32个字符长度。开始的时候,我给用户注册密码都是6位,我没弄清楚为什么在报错的时候,提示我是密码长度超出了设置的长度。于是我在MySQL的客户端上,重新查看了describe user命令查看了表结构,发现是32位,然后我于是通过SHOW VARIABLES LIKE 'validate_password%'命令,去查看密码等级的设置,并没有出现设置不匹配的原因,后来我查了很多资料,问了老师,才知道,是在密码加密之后,密码长度会变长,于是我就设置成128位。


5. 项目中最难的一个知识点

我认为,在这个项目中最难的一个知识点是对于如何去使用websocketpp去搭建服务器这个点上。因为在做这个项目之前,我都只用过HTTP去做过一个简单的服务器,没有拓展到去学习websocket协议,从而使用websocket去搭建一个拥有HTTP协议和websocket协议的服务器。


6. 有想过怎么扩展吗

想过给下棋玩家设置一个时间限制,在规定时间内没有下棋动作,那么就直接轮到对方下棋。

还有就是增加一个AI选手,可以让玩家与AI进行对战。

项目整体代码链接

代码链接

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

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

相关文章

图的遍历之 深度优先搜索和广度优先搜索

深度优先搜索的图文介绍 1. 深度优先搜索介绍 图的深度优先搜索(Depth First Search)&#xff0c;和树的先序遍历比较类似。 它的思想&#xff1a;假设初始状态是图中所有顶点均未被访问&#xff0c;则从某个顶点v出发&#xff0c;首先访问该顶点&#xff0c;然后依次从它的各…

亚马逊 EC2服务器下部署java环境

1. jdk 1.8 安装 1.1 下载jdk包 官网 Java Downloads | Oracle tar.gz 包 下载下来 1.2 本地连接 服务器 我用的是亚马逊的ec2 系统是 ubuntu 的 ssh工具是 Mobaxterm , 公有dns 创建实例时的秘钥 链接 Mobaxterm 因为使用的 ubuntu 所以登录的 名称 就是 ubuntu 然后 …

Leetcode每日一题:2681. 英雄的力量(2023.8.1 C++)

目录 2681. 英雄的力量 题目描述&#xff1a; 实现代码与解析&#xff1a; 数学规律 原理思路&#xff1a; 2681. 英雄的力量 题目描述&#xff1a; 给你一个下标从 0 开始的整数数组 nums &#xff0c;它表示英雄的能力值。如果我们选出一部分英雄&#xff0c;这组英雄的…

【kubeadm的配置安装】

目录 一、环境准备二、所有节点安装docker三、部署K8S集群1、查看镜像2、初始化kubeadm方法一&#xff1a;1、修改配置文件2、在线拉取镜像3、初始化 master 方法二、 3、设定kubectl4、所有节点部署网络插件flannel 四、部署 Dashboard1、在 master01 节点上操作 master&#…

分布式事务面试题

一、事务简介 事务(Transaction)是操作数据库中某个数据项的一个程序执行单元(unit)。 事务应该具有4个属性&#xff1a;原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。 1.1、名词解释 事务&#xff1a;事务是由一组操作构成的可靠的独立的工作单元&#x…

【前端】Vue生命周期函数(详细讲解+中文图解)

目录 一、何为生命周期1、含义2、理解 二、生命周期定义&#xff08;官网&#xff09;1、vue22、vue3 三、生命周期图解1、vue2生命周期图解2、vue3生命周期图解 四、Vue的生命周期五、Vue2生命周期和Vue3生命周期的区别六、Vue生命周期的主要阶段以及8个周期函数1、options AP…

BM5 合并k个已排序的链表 javascript

描述 合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。 数据范围&#xff1a; 示例1 输入&#xff1a; [{1,2,3},{4,5,6,7}] 返回值&#xff1a; {1,2,3,4,5,6,7}示例2 输入&#xff1a; [{1,2},{1,4,5},{6}] 返回值&#xff1a; {1,1,2,4,5,6}解题思路 利用两个…

Python numpy中的correlate相关性详解

看代码看见这个方法&#xff0c;记录一下&#xff0c;这个是人家官网的链接np.correlate 云里雾里的&#xff0c;其实就是两个数组点乘&#xff0c;不同模式就是错位点乘&#xff0c;直接看代码 a是原本的数组&#xff0c;v就是滤波器&#xff0c;对应相乘 import numpy as …

分布式 - 消息队列Kafka:Kafka生产者发送消息的3种方式

文章目录 1. Kafka 生产者2. kafaka 命令行操作3. Kafka 生产者发送消息流程4. Kafka 生产者发送消息的3种方式1. 发送即忘记2. 同步发送3. 异步发送 5. Kafka 消息对象 ProducerRecord 1. Kafka 生产者 Kafka 生产者是指使用 Apache Kafka 消息系统的应用程序&#xff0c;它们…

什么是React?React与VU的优缺点有哪些?

什么是React&#xff1f;什么是VUE&#xff1f; 维基百科上的概念解释&#xff0c;Vue.js是一个用于创建用户界面的开源MVVM前端JavaScript框架&#xff0c;也是一个创建单页应用的Web应用框架。Vue.js由尤雨溪&#xff08;Evan You&#xff09;创建&#xff0c;由他和其他活跃…

【Go语言】Golang保姆级入门教程 Go初学者chapter3

Go语言 第三章 运算符 下划线“_”本身在Go中一个特殊的标识符&#xff0c;成为空标识符。可以代表任何其他的标识符&#xff0c;但是他对应的值就会被忽略 仅仅被作为站维度使用&#xff0c; 不能作为标识符使用 因为Go语言中没有private public 所以标记变量首字母大写代表其…

Pytorch量化之Post Train Static Quantization(训练后静态量化)

使用Pytorch训练出的模型权重为fp32&#xff0c;部署时&#xff0c;为了加快速度&#xff0c;一般会将模型量化至int8。与fp32相比&#xff0c;int8模型的大小为原来的1/4, 速度为2~4倍。 Pytorch支持三种量化方式&#xff1a; 动态量化&#xff08;Dynamic Quantization&…

最大异或对

如果你觉得这篇题解对你有用&#xff0c;可以点个赞或关注再走呗&#xff0c;谢谢你的关注~ 分析 最大异或对 (1)最大异或对是运用trie树存储十进制数对应的二进制数的每一位。 (2)再根据trie树的每一位进行搜索查找&#xff0c;严格满足不同的数异或为1&#xff0c;相同的异…

【业余小练习】交互式网格自定义增删改(进行中)

学习SQL和PLISQL数据类型的区别和应用场景 Oracle plsql 基础篇1 数据类型以及流程控制_bb_tarek的博客-CSDN博客https://blog.csdn.net/bb_tarek/article/details/17555713?ops_request_misc&request_id&biz_id102&utm_termplsql%E5%9F%BA%E6%9C%AC%E6%95%B0%E6…

Unlikely argument type for equals(): String seems to be unrelated to T

Unlikely argument type for equals(): String seems to be unrelated to Integer Unlikely argument type for equals(): String seems to be unrelated to Date 多余代码

java代码审计9之XXE

文章目录 1、简介2、 java XXE审计函数3、漏洞3.1、正常的业务3.2、有回显的情况3.3、无回显的情况3.4、修复 之前的文章&#xff0c; php代码审计9之XXE 1、简介 XXE&#xff08;XML外部实体注⼊&#xff0c;XML External Entity) &#xff0c;在应⽤程序解析XML输⼊时&…

【雕爷学编程】Arduino动手做(200)---WS2812B幻彩LED灯带4

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

linux系统虚拟主机开启支持SourceGuardian(sg11)加密组件

注意&#xff1a;sg11我司只支持linux系统虚拟主机自主安装。支持php5.3及以上版本。 1、登陆主机控制面板&#xff0c;找到【远程文件下载】这个功能。 2、远程下载文件填写http://download.myhostadmin.net/vps/sg11_for_linux.zip 下载保存的路径填写/others/ 3、点击控制…

golang 自定义exporter - 端口连接数 portConnCount_exporter

需求&#xff1a; 1、计算当前6379 、3306 服务的连接数 2、可prometheus 语法查询 下面代码可直接使用&#xff1a; 注&#xff1a; 1、windows 与linux的区分 第38行代码 localAddr : fields[1] //windows为fields[1] &#xff0c; linux为fields[3] 2、如需求 增加/修改/删除…

PHP实现在线进制转换器,10进制,2、4、8、16、32进制转换

1.接口文档 2.laravel实现代码 /*** 进制转换计算器* return \Illuminate\Http\JsonResponse*/public function binaryConvertCal(){$ten $this->request(ten);$two $this->request(two);$four $this->request(four);$eight $this->request(eight);$sixteen …