当前位置: 首页 > news >正文

【在线五子棋对战】十一、整合封装服务器模块实现

文章目录

  • 前言
  • Ⅰ. 采用 RESTful 风格的数据格式规定
      • 1、静态资源请求
      • 2、注册用户
      • 3、用户登录
      • 4、获取客户端信息
      • 5、websocket长连接协议切换请求 -- 进入游戏大厅
      • 6、开始对战匹配
      • 7、取消匹配
      • 8、websocket长连接协议切换请求 -- 进入游戏房间
      • 9、下棋
      • 10、聊天
  • Ⅱ. 搭建websocket服务器框架

在这里插入图片描述

前言

​ 服务器模块,是对当前所实现的所有模块的一个整合,并进行服务器搭建的一个模块,最终封装实现出一个 gobang_server 的服务器模块类,向外提供搭建五子棋对战服务器的接口。通过实例化的对象可以简便的完成服务器的搭建。服务器的整合设计主要是分为下面两个过程:

  • 网络通信接口的设计
    • 收到一个什么格式的数据,是代表什么样的请求,要将该请求给什么样的业务处理以及响应
  • 搭建服务器
    • 搭建 websocket 服务器,实现网络通信
    • 针对各自不同的请求进行不同的业务处理

​ 那么可能客户端会发什么样的请求呢,如下图所示:

在这里插入图片描述

Ⅰ. 采用 RESTful 风格的数据格式规定

一杯茶的时间,搞懂 RESTful API

​ 整个项目的通信接口的设计,是采用 RESTful 风格的,如下图所示:

在这里插入图片描述

​ 下面我们先来了解整套通信时候的数据格式规定和响应数据格式的规定,因为我们的接口设计也是要按照这些规定来的!

1、静态资源请求

​ 静态资源页面,在后台服务器上就是个 html/css/js 文件,而静态资源请求的处理,其实就是将文件中的内容发送给客户端。

​ 比如我们的项目中,静态资源请求其实只有四种:

  • 注册页面请求

    请求格式:GET /register.html HTTP/1.1
    响应格式:
    HTTP/1.1 200 OK
    Content-Length: xxx
    Content-Type: text/htmlregister.html⽂件的内容数据
    
  • 登录页面请求

    GET /login.html HTTP/1.1
    
  • 大厅页面请求

    GET /game_hall.html HTTP/1.1
    
  • 房间页面请求

    GET /game_room.html HTTP/1.1
    

2、注册用户

POST /reg HTTP/1.1
Content-Type: application/json
Content-Length: 32
{"username":"xiaobai", "password":"123123"}
#成功时的响应
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 15
{"result":true}
#-------------------------------------------------
#失败时的响应
HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 43
{"result":false, "reason": "用户名已被占用"}

3、用户登录

​ 登录的请求类型也是 POST,因为我们要提交数据!

POST /login HTTP/1.1
Content-Type: application/json
Content-Length: 32
{"username":"xiaobai", "password":"123123"}
#成功时的响应
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 15
{"result":true}
#-------------------------------------------------
#失败时的响应
HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 43
{"result":false, "reason": "用户名或密码错误"}

4、获取客户端信息

GET /info HTTP/1.1
Content-Type: application/json
Content-Length: 0
#成功时的响应
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 58
{"id":1, "username":"xiaobai", "score":1000, "total_count":4, "win_count":2}
#-------------------------------------------------
#失败时的响应
HTTP/1.1 401 Unauthorized
Content-Type: application/json
Content-Length: 43
{"result":false, "reason": "用户还未登录"}

5、websocket长连接协议切换请求 – 进入游戏大厅

​ 当服务器收到了切换为 websocket 协议的时候会帮我们自动切换!

/* ws://localhost:9000/hall */
GET /hall HTTP/1.1
Connection: Upgrade
Upgrade: WebSocket
......
HTTP/1.1 101 Switching
......

WebSocket 握手成功后的回复:表示游戏大厅已经进入成功,此时响应:

{
"optype": "hall_ready",
"uid": 1
}

6、开始对战匹配

​ 这种情况比较特殊,我们要在加入匹配队列和匹配成功的时候都给客户端发送响应!

{
"optype": "match_start"
}
/* 后台正确处理后回复 */
{
"optype": "match_start",      // 表示成功加入匹配队列
"result": true
}
#-------------------------------------------------
/* 后台处理出错回复 */
{
"optype": "match_start"
"result": false,
"reason": "具体原因...."
}
/* 匹配成功了给客户端的回复 */
{
"optype": "match_success",     // 表示匹配成功
"result": true
}

7、取消匹配

{
"optype": "match_stop"
}
/*后台正确处理后回复*/
{
"optype": "match_stop"
"result": true
}
#-------------------------------------------------
/*后台处理出错回复*/
{
"optype": "match_stop"
"result": false,
"reason": "具体原因...."}

8、websocket长连接协议切换请求 – 进入游戏房间

注意进入大厅和房间的 websocket 连接是不同的,所以要再次进行切换!

/* ws://localhost:9000/room */
GET /room HTTP/1.1
Connection: Upgrade
Upgrade: WebSocket
......
HTTP/1.1 101 Switching
......

WebSocket 握手成功后的回复:表示游戏房间已经进入成功,此时响应:

/* 协议切换成功,房间已经建立 */
{
"optype": "room_ready",
"room_id": 222,  // 房间ID
"self_id": 1,    // 自身ID
"white_id": 1,   // 白棋ID
"black_id": 2,   // 黑棋ID
}

9、下棋

{
"optype": "put_chess",  // put_chess 表示当前请求是下棋操作
"room_id": 222, 		// room_id 表示当前动作属于哪个房间
"uid": 1, 				// 当前的下棋操作是哪个用户发起的
"row": 3, 				// 当前下棋位置的行号
"col": 2 				// 当前下棋位置的列号
}
{
"optype": "put_chess",
"result": false
"reason": "⾛棋失败具体原因...."
}
#-------------------------------------------------
{
"optype": "put_chess",
"result": true,
"reason": "对方掉线,不战而胜!" / "对方/己方五星连珠,战无敌/虽败犹荣!",
"room_id": 222,
"uid": 1,
"row": 3,
"col": 2,
"winner": 0 			// 0表示未分胜负,非0表示已分胜负 (uid是谁,谁就赢了)
}

10、聊天

{
"optype": "chat",
"room_id": 222,
"uid": 1,
"message": "赶紧点"
}
{
"optype": "chat",
"result": false
"reason": "聊天失败具体原因....比如有敏感词..."
}
#-------------------------------------------------
{
"optype": "chat",
"result": true,
"room_id": 222,
"uid": 1,
"message": "赶紧点"
}

Ⅱ. 搭建websocket服务器框架

​ 因为我们之前的模块都是为服务器做准备的,所以直接将这些模块在服务器类中进行实例化和初始化即可!要注意的是初始化的顺序是有讲究的,因为有些类是依赖其它类的,那些被依赖的类应该先初始化最好还要将声明位置也改一下,保持和初始化顺序一致

​ 而服务器的搭建我们之前也有学过,就是调用几个接口,然后通过再通过 start() 函数进行服务器的启动!

#ifndef __MY_SERVER_H__
#define __MY_SERVER_H__
#include "db.hpp"
#include "online.hpp"
#include "util.hpp"
#include "session.hpp"
#include "matcher.hpp"
#include "room.hpp"#define WEBROOT "./wwwroot/"class gobang_server
{
private:std::string _webroot;        // 静态资源目录,默认为./wwwroot/wsserver_t _server;          // websocket服务器实例user_table _user_table;      // 数据库用户信息实例online_manager _online_user; // 在线用户管理实例session_manager _session;    // 会话管理实例room_manager _room;          // 房间管理实例match_manager _matcher;      // 匹配管理实例
private:void http_callback(websocketpp::connection_hdl hdl){}void open_callback(websocketpp::connection_hdl hdl){}void close_callback(websocketpp::connection_hdl hdl){}void message_callback(websocketpp::connection_hdl hdl, wsserver_t::message_ptr msgptr){}
public:// 构造函数,完成成员变量的初始化以及服务器的设置gobang_server(const std::string& host,const std::string& user,const std::string& passwd,const std::string& dbname,uint16_t port = 3306,const std::string& webroot = WEBROOT): _webroot(webroot), _user_table(host, user, passwd, dbname, port), _session(&_server), _room(&_user_table, &_online_user), _matcher(&_online_user, &_user_table, &_room){// 设置日志等级_server.set_access_channels(websocketpp::log::alevel::none);// 初始化asio调度器和地址重用_server.init_asio();_server.set_reuse_addr(true);// 设置回调函数_server.set_http_handler(std::bind(&gobang_server::http_callback, this, std::placeholders::_1));_server.set_open_handler(std::bind(&gobang_server::open_callback, this, std::placeholders::_1));_server.set_close_handler(std::bind(&gobang_server::close_callback, this, std::placeholders::_1));_server.set_message_handler(std::bind(&gobang_server::message_callback, this, std::placeholders::_1, std::placeholders::_2));}// 启动服务器接口void start(uint16_t port){_server.listen(port);   // 设置监听窗口_server.start_accept(); // 开始获取新连接_server.run();          // 启动服务器}
};#endif

​ 下面为了测试服务器是否搭建成功,我们在 http_callback() 函数里面,对浏览器发送的 http 请求,返回对应的静态资源,代码如下:

void http_callback(websocketpp::connection_hdl hdl)
{wsserver_t::connection_ptr conn = _server.get_con_from_hdl(hdl);websocketpp::http::parser::request req = conn->get_request();std::string pathname = _webroot + req.get_uri();std::string body;file_util::read(pathname, body);conn->set_status(websocketpp::http::status_code::ok);conn->set_body(body);
}

​ 编译之后执行可执行文件,然后通过浏览器输入对应的服务器 IP 和端口号和资源路径就能请求到对应的 html 等文件!注意这只是测试代码,后面这段代码是不存在的!

​ 下面我们针对不同的请求进行不同的业务处理,划分为 http请求websocket长连接请求 两部分进行设计和实现!

在这里插入图片描述

http://www.dtcms.com/a/308406.html

相关文章:

  • linux git ssh配置过程
  • chrome.storage 和 localStorage
  • 自动化与配置管理工具 ——SaltStack
  • 用 AI 自动生成口型同步视频,短视频内容也能一人完成
  • 基于深度学习的医学图像分析:使用YOLOv5实现医学图像目标检测
  • 测试平台进化论:如何在CI/CD时代重构软件质量防线
  • # 前端开发规范基础汇总
  • 掌握Python三大语句:顺序、条件与循环
  • 深度解析:基于Python构建的闲鱼自动化营销与信息发送机器人
  • 暄桐:如何脱离“不学无术”的状态?
  • 集成学习方法之随机森林:从原理到实战的深度解析
  • pip库版本升级
  • vue vxe-table :edit-config=“editConfig“ 可以编辑的表格
  • Netcat终极实战指南:从端口扫描到渗透测试
  • Multimodal Fusion on Low-quality Data: A Comprehensive Survey 中文版
  • Java面试高频题目
  • 基于notepad++的sensor寄存器序列文本处理方法(以后会随时更新补充)
  • STM32F1到STM32F0的标准库移植指南--GPIO篇
  • 认知绞肉机:个体实践视域下认知暴力与元认知升维的活体实验研究
  • 如何将 Redis 监控集成到微服务整体的监控体系中( 如 Prometheus + Grafana)
  • [12月考试] E
  • 使用EasyPOI实现Java订单数据导出(含多物料信息)——模板语法详解与实战
  • Redis实战(4)-- BitMap结构与使用
  • uvicorn 启动重复加载 多次加载
  • 【LeetCode 热题 100】4. 寻找两个正序数组的中位数——(解法一)线性扫描
  • C++(模板)
  • java笔记——ConcurrentLinkedQueue
  • AUTOSAR进阶图解==>AUTOSAR_SRS_FunctionInhibitionManager
  • axios封装对比
  • 记录自己使用gitee和jenkins