巢湖市建设工程网站某公司网站建设策划书
web/
2025/9/28 8:22:18/
文章来源:
巢湖市建设工程网站,某公司网站建设策划书,网站制作论文优帮云,西安黄页88网企业名录服务器模块#xff0c;是对当前所实现的所有模块的⼀个整合#xff0c;并进⾏服务器搭建的⼀个模块#xff0c;最终封装实现出⼀个gobang_server的服务器模块类#xff0c;向外提供搭建五⼦棋对战服务器的接⼝。通过实例化的对象可以简便的完成服务器的搭建。
服务器框架 …服务器模块是对当前所实现的所有模块的⼀个整合并进⾏服务器搭建的⼀个模块最终封装实现出⼀个gobang_server的服务器模块类向外提供搭建五⼦棋对战服务器的接⼝。通过实例化的对象可以简便的完成服务器的搭建。
服务器框架
首先我将采用websocketpp来搭建服务器那么需要清楚的是搭建服务器的流程 1.实例化出server对象 2.设置日志等级 3.初始化asio调度器 4.设置回调函数 5.设置监听端口 6.开始获取新连接 7.启动服务器 #ifndef __M_SRV_H__
#define __M_SRV_H__
#include db.hpp
#include matcher.hpp
#include online.hpp
#include room.hpp
#include session.hpp
#include util.hpp#define WWWROOT ./wwwroot/
class gobang_server
{
private: std::string _web_root;//静态资源根目录 ./wwwroot/wsserver_t _wssrv;user_table _ut;online_manager _om;room_manager _rm;matcher _mm;session_manager _sm;
private://http请求处理回调函数void http_callback(wsserver_t* srv,websocketpp::connection_hdl hdl){}// websocket连接成功的回调函数void wsopen_callback(wsserver_t* srv,websocketpp::connection_hdl hdl){}// websocket关闭连接成功的回调函数void wsclose_callback(wsserver_t* srv,websocketpp::connection_hdl hdl){}// websocket连接收到消息的回调函数void wsmsg_callback(wsserver_t* srv,websocketpp::connection_hdl hdl,wsserver_t::message_ptr msg){}
public:gobang_server(onst std::string host,const std::string user,const std::string pass,const std::string dbname,uint16_t port 3306,const std::string wwwroot WWWROOT)_web_root(wwwroot), _ut(host, user, pass, dbname, port),_rm(_ut, _om), _sm(_wssrv), _mm(_rm, _ut, _om){//设置日志等级_wssrv.set_access_channels(websocketpp::log::alevel::none);/*禁止日志等级不打印*///初始化asio调度器_wssrv.init_asio();_wssrv.set_reuse_addr(true);//设置回调函数_wssrv.set_http_handler(std::bind(gobang_server::http_callback,this,std::placeholders::_1));_wssrv.set_open_handler(std::bind(gobang_server::wsopen_callback,this,std::placeholders::_1));_wssrv.set_close_handler(std::bind(gobang_server::wsclose_callback,this,std::placeholders::_1));_wssrv.set_message_handler(std::bind(gobang_server::wsmsg_callback,this,std::placeholders::_1,std::placeholders::_2));}void start(int port){//1.设置监听端口_wssrv.listen(8888);//2.开始获取新连接_wssrv.start_accept();//3.启动服务器_wssrv.run();}};#endif
1.http请求回调处理函数
需要用到HTTP请求进行短连接的是用户注册、用户登录和获取用户信息的功能请求处理以及静态资源请求处理的方法。
①静态资源请求处理
当我们打开客户端迎面而来的是登录页面因此在静态资源请求处理中我们需要获取到登录页面的实际路径。
流程首先需要获取HTTP请求的对象通过请求对象获取到HTTP请求中的uri然后将uri和根目录路径进行组合组合成为实际路径。然后通过read来读取文件内容并将其返回响应。 /*静态资源请求处理*/void file_handler(wsserver_t::connection_ptr conn){/*对于静态资源的请求我们需要先获取HTTP请求对象然后通过请求对象获取HTTP请求中的uri*///1.获取到请求uri--资源路径要了解客户端的页面文件名称websocketpp::http::parser::request req conn-get_request();std::string uri req.get_uri();//2.组合出文件的实际路径 相对根目录uristd::string realpath _web_rooturi;//3.如果在实际路径中最后的字符是/那么表示是目录的路径需要再加上静态资源的路径if(realpath.back()/)//目录{realpathlogin.html;//}//4.读取文件内容std::string body;bool ret file_util::read(realpath,body);//如果文件不存在则读取失败返回404if(retfalse){body html;body head;body meta charsetUTF-8/;body /head;body body;body h1 Not Found /h1;body /body;conn-set_status(websocketpp::http::status_code::not_found);conn-set_body(body);return;}//5.设置响应正文conn-set_status(websocketpp::http::status_code::ok);conn-set_body(body);}
②用户注册请求处理
用户注册请求处理首先通过通信连接获取到HTTP请求的正文然后对正文进行反序列化得到用户和密码。接着对用户和密码进行完整性校验若是完整那么通过数据模块管理对象进行插入完成注册最后将注册完成响应回给客户端。
其中的http_resp方法是封装了响应信息的填充。包括了原因、结果以及将其序列化后返回给客户端。 void http_resp(wsserver_t::connection_ptr conn,bool result, websocketpp::http::status_code::value code,const std::string reason){Json::Value resp_json;resp_json[result] result;resp_json[reason] reason;std::string resp_body;json_util::serialize(resp_json,resp_body);conn-set_status(code);conn-set_body(resp_body);conn-append_header(Content-Type, application/json);return;}/*用户注册请求处理*/void reg(wsserver_t::connection_ptr conn){/*从前端页面中获取数据然后新增进数据库中并且成功就代表注册成功*///1.获取正文内容//先获取请求对象然后通过连接获取请求正文websocketpp::http::parser::request req conn-get_request();std::string req_body conn-get_request_body();//2.对正文内容进行反序列化得到用户和密码Json::Value login_info;bool ret json_util::unserialize(req_body,login_info);if(retfalse){DLOG(反序列化注册信息失败);return http_resp(conn,false,websocketpp::http::status_code::bad_request,请求正文格式错误);}//3.进行数据库的插入if(login_info[username].isNull() || login_info[password].isNull()){DLOG(⽤⼾名密码不完整);return http_resp(conn,false,websocketpp::http::status_code::bad_request,请输入用户名/密码);}ret _ut.insert(login_info);if(retfalse){DLOG(向数据库插⼊数据失败);return http_resp(conn,false,websocketpp::http::status_code::bad_request,用户名已经被占用);}return http_resp(conn,true,websocketpp::http::status_code::ok,注册成功);}
注册请求前端页面
!DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0title注册/titlelink relstylesheet href./css/common.csslink relstylesheet href./css/login.css
/headbodydiv classnav⽹络五⼦棋对战游戏/divdiv classlogin-container!-- 登录界⾯的对话框 --div classlogin-dialog!-- 提⽰信息 --h3注册/h3!-- 这个表⽰⼀⾏ --div classrowspan⽤⼾名/spaninput typetext iduser_name nameusername/div!-- 这是另⼀⾏ --div classrowspan密码/spaninput typepassword idpassword namepassword/div!-- 提交按钮 --div classrowbutton idsubmit onclickreg()提交/button/div/div/divscript srcjs/jquery.min.js/scriptscript//1. 给按钮添加点击事件调⽤注册函数//2. 封装实现注册函数function reg() {// 1. 获取两个输⼊框空间中的数据组织成为⼀个json串var reg_info {username: document.getElementById(user_name).value,password: document.getElementById(password).value};console.log(JSON.stringify(reg_info));// 2. 通过ajax向后台发送⽤⼾注册请求$.ajax({url: /reg,type: post,data: JSON.stringify(reg_info),success: function (res) {if (res.result false) {// 4. 如果请求失败则清空两个输⼊框内容并提⽰错误原因document.getElementById(user_name).value ;document.getElementById(password).value ;alert(res.reason);} else {// 3. 如果请求成功则跳转的登录⻚⾯alert(res.reason);window.location.assign(/login.html);}},error: function (xhr) {document.getElementById(user_name).value ;document.getElementById(password).value ;alert(JSON.stringify(xhr));}})}/script
/body/html
③用户登录请求处理
流程
首先获取到HTTP请求正文然后将其反序列化后得到用户的账号和密码。接着对账号密码进行校验并查询到该用户的所有信息。然后为该用户创建sessionsession创建成功后为HTTP响应中的cookie信息填入该session的sid。最后将信息响应给客户端。 /*用户登录请求处理*/void login(wsserver_t::connection_ptr conn){//1.获取正文信息并进行反序列化得到用户账号和密码std::string resp_body conn-get_request_body();Json::Value login_info;bool ret json_util::unserialize(resp_body,login_info);if(retfalse){DLOG(反序列化登录信息失败);return http_resp(conn,false,websocketpp::http::status_code::bad_request,反序列化登录信息失败);}//2.对账户和密码进行校验并且将该用户的信息全部填充到login_info中ret _ut.login(login_info);if(retfalse){DLOG(用户名或密码错误);return http_resp(conn,false,websocketpp::http::status_code::bad_request,用户名或密码错误);}//3.登录成功后为用户创建sessionuint64_t uid login_info[id].asUInt64();session_ptr ssp _sm.create_session(uid,LOGIN);if(ssp.get()nullptr){DLOG(创建会话失败);return http_resp(conn,false,websocketpp::http::status_code::bad_request,创建会话失败);}//4.session创建成功后设置响应头部Set-Cookie,将session通过cookie返回/*将在HTTP响应中将其中的cookie信息填入SSID...*/std::string cooike_ssid SSIDstd::to_string(ssp-ssid());/*填入cookie信息*/conn-append_header(Set-Cookie,cooike_ssid);//登录完成将信息响应回给客户端return http_resp(conn,true,websocketpp::http::status_code::ok,登录成功);}
登录请求前端页面
!DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0title登录/titlelink relstylesheet href./css/common.csslink relstylesheet href./css/login.css
/headbodydiv classnav网络五子棋对战游戏/divdiv classlogin-container!-- 登录界面的对话框 --div classlogin-dialog!-- 提示信息 --h3登录/h3!-- 这个表示一行 --div classrowspan用户名/spaninput typetext iduser_name/div!-- 这是另一行 --div classrowspan密码/spaninput typepassword idpassword/div!-- 提交按钮 --div classrowbutton idsubmit onclicklogin()提交/button/div/div/divscript src./js/jquery.min.js/scriptscript//1. 给按钮添加点击事件调用登录请求函数//2. 封装登录请求函数function login() {// 1. 获取输入框中的用户名和密码并组织json对象var login_info {username: document.getElementById(user_name).value,password: document.getElementById(password).value};// 2. 通过ajax向后台发送登录验证请求$.ajax({url: /login,type: post,data: JSON.stringify(login_info),success: function (result) {// 3. 如果验证通过则跳转游戏大厅页面alert(登录成功);window.location.assign(/game_hall.html);},error: function (xhr) {// 4. 如果验证失败则提示错误信息并清空输入框alert(JSON.stringify(xhr));document.getElementById(user_name).value ;document.getElementById(password).value ;}})}/script
/body/html
④获取用户信息请求处理
在登录账号进入游戏大厅中后游戏大厅需要显示该用户的所有信息。因此在获取用户信息请求的处理中首先通过HTTP请求中的cookie信息找到对应的session的ssid接着通过ssid找到对应的session对话信息从对话信息中找到用户id接着通过用户id从数据库中查询到该用户的信息并存储在Json对象中接着将其序列化最后响应回给客户端。最后一步登录之后需要刷新session的定时器的过期时间。
方法get_cookie_val是将cookie中提取ssid的方法cookie中的每一个信息是以; 作为分隔符的。 bool get_cookie_val(const std::string cookie_str,const std::string key,std::string val){std::string sep; ;std::vectorstd::string cookie_arr;string_util::split(cookie_str, sep, cookie_arr);for(auto str:cookie_arr){std::vectorstd::string tmp_arr;string_util::split(str,,tmp_arr);if(tmp_arr.size()!2){continue;}if(tmp_arr[0]key){val tmp_arr[1];return true;}}return false;}/*用户信息获取功能请求处理*/void info(wsserver_t::connection_ptr conn){//⽤⼾信息获取功能请求的处理Json::Value err_resp;// 1. 获取请求信息中的Cookie从Cookie中获取ssidstd::string cookie_str conn-get_request_header(Cookie);if (cookie_str.empty()) {//如果没有cookie返回错误没有cookie信息让客⼾端重新登录return http_resp(conn, true,websocketpp::http::status_code::bad_request, 找不到cookie信息请重新登录);}// 1.5. 从cookie中取出ssidstd::string ssid_str;bool ret get_cookie_val(cookie_str, SSID, ssid_str);if (ret false) {//cookie中没有ssid返回错误没有ssid信息让客⼾端重新登录return http_resp(conn, true,websocketpp::http::status_code::bad_request, 找不到ssid信息请重新登录);}// 2. 在session管理中查找对应的会话信息session_ptr ssp _sm.get_session_by_ssid(std::stol(ssid_str));if (ssp.get() nullptr) {//没有找到session则认为登录已经过期需要重新登录return http_resp(conn, true,websocketpp::http::status_code::bad_request, 登录过期请重新登录);}// 3. 从数据库中取出⽤⼾信息进⾏序列化发送给客⼾端uint64_t uid ssp-get_user();Json::Value user_info;ret _ut.select_by_id(uid, user_info);if (ret false){//获取⽤⼾信息失败返回错误找不到⽤⼾信息return http_resp(conn, true,websocketpp::http::status_code::bad_request, 找不到用户信息请重新登录);}std::string body;json_util::serialize(user_info, body);conn-set_body(body);conn-append_header(Content-Type, application/json);conn-set_status(websocketpp::http::status_code::ok);// 4. 刷新session的过期时间_ss.set_session_expire_time(ssp-ssid(), SESSION_TIMEOUT);}
HTTP请求回调处理函数
在回调函数中通过HTTP请求中的方法和uri来判断需要处理的业务是哪个因此首先需要获取客户端通信连接然后通过通信连接获取HTTP请求对象通过HTTP请求对象获取uri和方法。
然后通过方法和uri来确定需要处理的业务是哪个 void http_callback(websocketpp::connection_hdl hdl){wsserver_t::connection_ptr conn _wssrv.get_con_from_hdl(hdl);websocketpp::http::parser::request req conn-get_request();std::string method req.get_method();std::string uri req.get_uri();if (method POST uri /reg) {return reg(conn);}else if (method POST uri /login) {return login(conn);}else if (method GET uri /info) {return info(conn);}else {return file_handler(conn);}}
2.websocket连接成功的回调函数
websocket连接成功的回调函数在websocket长连接建立成功后主要处理的两个业务 1.游戏大厅长连接的建立 2.游戏房间的长连接的建立 ①游戏大厅长连接的建立
想要成功建立游戏大厅的长连接首先需要通过通信连接获取到session对话信息获取session对话信息主要是需要获得该客户端的用户uid然后将用户uid和通信连接加入到游戏大厅中。
对于通过通信连接获取session对话信息则是通过通信连接获取websocket请求中的cookie然后从cookie中获取ssid然后通过ssid在session管理中查找对应的session会话信息。 void ws_resp(wsserver_t::connection_ptr conn,Json::Value resp){std::string body;json_util::serialize(resp,body);conn-send(body);}//找到session对话信息session_ptr get_session_by_cookie(wsserver_t::connection_ptr conn){/*通过通信连接获取websocket请求中的cookie然后从cookie中获取ssid取出ssid后通过ssid最终获取session对话信息*/Json::Value err_resp;//1.获取请求信息中的Cookie从Cookie中获取ssidstd::string cookie_str conn-get_request_header(Cookie);if(cookie_str.empty()){err_resp[optype]hall_ready;err_resp[reason] 没有找到cookie信息需要重新登录;err_resp[result]false;//把错误信息响应回去ws_resp(conn,err_resp);return session_ptr();}//1.1 获取cookie信息成功后取出ssidstd::string ssid_str;bool ret get_cookie_val(cookie_str,SSID,ssid_str);if(retfalse){err_resp[optype]hall_ready;err_resp[reason] 没有找到SSID信息需要重新登录;err_resp[result]false;//把错误信息响应回去ws_resp(conn,err_resp);return session_ptr();}//2. 通过ssid在session管理中查找对应的会话信息session_ptr ssp _sm.get_session_by_ssid(std::stol(ssid_str));if(ssp.get()nullptr){err_resp[optype]hall_ready;err_resp[reason] 没有找到session信息需要重新登录;err_resp[result]false;//把错误信息响应回去ws_resp(conn,err_resp);return session_ptr();}return ssp;}void wsopen_game_hall(wsserver_t::connection_ptr conn){//游戏大厅长连接建立成功Json::Value resp_json;//1.登录验证--判断当前客户端是否已经成功登录session_ptr ssp get_session_by_cookie(conn);if(ssp.get()nullptr){return;}//2.判断当前客户端是否异地登陆if(_om.is_in_game_hall(ssp-get_user()) || _om.is_in_game_room(ssp-get_user())) {resp_json[optype] hall_ready;resp_json[reason] 玩家重复登录;resp_json[result] false;return ws_resp(conn, resp_json);}//3. 将当前客⼾端以及连接加⼊到游戏⼤厅_om.enter_game_hall(ssp-get_user(), conn);//4. 给客⼾端响应游戏⼤厅连接建⽴成功resp_json[optype] hall_ready;resp_json[result] true;ws_resp(conn, resp_json);//5. 记得将session设置为永久存在_sm.set_session_expire_time(ssp-ssid(), SESSION_FOREVER);}
②游戏房间长连接的建立
与游戏大厅长连接的建立差不多首先通过通信连接获取到该客户端的session然后通过session获取到用户的uid然后将当前用户添加到在线用户管理的房间当中。还需通过uid获取到对应的房间信息将房间信息响应给客户端。 void wsopen_game_room(wsserver_t::connection_ptr conn){//游戏房间长连接建立成功Json::Value resp_json;//1.获取当前客户端的sessionsession_ptr ssp get_session_by_cookie(conn);if(ssp.get()nullptr){return;}//2.判断当前用户是否已经在在线用户管理的游戏房间或游戏大厅中--如果在不能异地登陆/重复登录if(_om.is_in_game_hall(ssp-get_user()) || _om.is_in_game_room(ssp-get_user())){resp_json[optype] room_ready;resp_json[reason] 玩家重复登录;resp_json[result] false;return ws_resp(conn,resp_json);}//3.判断当前用户已经是否创建好了房间--房间管理//根据用户id获取所在的房间的信息room_ptr rp _rm.get_room_by_uid(ssp-get_user());if(rp.get()nullptr){resp_json[optype] room_ready;resp_json[reason] 没有找到玩家房间的信息;resp_json[result] false;return ws_resp(conn,resp_json);}//4.将当前用户添加到在线用户管理的房间当中_om.enter_game_room(ssp-get_user(),conn);//5.将session设置为永久存在_sm.set_session_expire_time(ssp-ssid(), SESSION_FOREVER);//6.将房间准备响应回去resp_json[optype] room_ready;resp_json[result] true;resp_json[room_id] (Json::UInt64)rp-get_rid();resp_json[uid] (Json::UInt64)ssp-get_user();resp_json[white_id] (Json::UInt64)rp-get_white_user();resp_json[black_id] (Json::UInt64)rp-get_black_user();return ws_resp(conn,resp_json);}
websocket长连接建立成功的回调函数
通过通信连接获取到websocket请求对象进而获取到uri通过uri来判断业务的请求。 /*游戏大厅长连接处理*/void wsopen_callback(websocketpp::connection_hdl hdl){//从uri中获取资源路径从而得知是游戏房间的请求还是游戏大厅的请求wsserver_t::connection_ptr conn _wssrv.get_con_from_hdl(hdl);websocketpp::http::parser::request req conn-get_request();std::string uri req.get_uri();if(uri/hall){//获取的是游戏大厅的长连接return wsopen_game_hall(conn);}else if(uri/room){//获取的是游戏房间的长连接return wsopen_game_room(conn);}}
3.websocket关闭连接的回调函数
websocket连接关闭的回调函数在websocket长连接关闭成功后主要处理的两个业务 1.游戏大厅长连接的关闭 2.游戏房间的长连接的关闭 ①游戏大厅长连接的关闭
通过通信连接获取session对话信息通过session对话信息获取uid然后将玩家从游戏大厅中移除最后重新设置session定时器定时删除。 //游戏大厅关闭长连接void wsclose_game_hall(wsserver_t::connection_ptr conn){//游戏⼤厅⻓连接断开的处理//1. 登录验证--判断当前客⼾端是否已经成功登录session_ptr ssp get_session_by_cookie(conn);if(ssp.get()nullptr){return;}//2.将玩家从大厅中移除_om.exit_game_hall(ssp-get_user());//2.将session恢复声明周期管理设置定时删除_sm.set_session_expire_time(ssp-ssid(),SESSION_TIMEOUT);}
②.游戏房间的长连接的关闭
通过通信连接获取session对话信息然后通过session对话信息获取到uid将玩家从在线用户管理中移除重新设置定时器最后将玩家从房间中移除。 //游戏房间关闭长连接void wsclose_game_room(wsserver_t::connection_ptr conn){//获取会话信息识别客⼾端session_ptr ssp get_session_by_cookie(conn);if(ssp.get()nullptr){return;}//2.将玩家从在线用户管理中移除_om.exit_game_room(ssp-get_user());//3.将session恢复声明周期管理设置定时删除_sm.set_session_expire_time(ssp-ssid(),SESSION_TIMEOUT);//4.将玩家从房间移除_rm.remove_room_user(ssp-get_user());}
websocket长连接关闭成功的回调函数
获取客户端的通信连接通过通信连接获取到websocket请求对象通过请求对象获取uri通过uri判断业务的处理请求。
void wsclose_callback(websocketpp::connection_hdl hdl){//从uri中获取资源路径从而得知是游戏房间的请求还是游戏大厅的请求wsserver_t::connection_ptr conn _wssrv.get_con_from_hdl(hdl);websocketpp::http::parser::request req conn-get_request();std::string uri req.get_uri();if(uri/hall){//获取的是游戏大厅的长连接return wsclose_game_hall(conn);}else if(uri/room){//获取的是游戏房间的长连接return wsclose_game_room(conn);}}
4. websocket连接收到消息的回调函数
websocket连接收到消息主要是两种业务处理请求 1.游戏大厅中的匹配对战 2.房间中的下棋或聊天动作 ① 在游戏大厅中开始进行匹配对战
首先需要获取两样东西第一个是通过通信连接获取session对话信息。第二个是获取请求的消息。
先是将请求消息进行反序列化得到匹配对战的相关内容根据内容处理不同的情况
情况一开始匹配对战。
在这种情况下通过session对话信息获取uid然后将玩家添加到匹配队列当中然后将信息向客户端进行响应。
情况二匹配中止。
在这种情况下通过session对话信息获取uid然后i将玩家从匹配队列中移除然后将信息向客户端进行相应。
情况三未知消息的处理。 //在游戏大厅中开始进行匹配对战void wsmsg_game_hall(wsserver_t::connection_ptr conn,wsserver_t::message_ptr msg){Json::Value resp_json;std::string resp_body;//1.身份验证看看当前客户端是哪个玩家session_ptr ssp get_session_by_cookie(conn);if(ssp.get()nullptr){return;}//2.获取请求信息std::string req_body msg-get_payload();Json::Value req_json;bool ret json_util::unserialize(req_body,req_json);if(retfalse){resp_json[result] false;resp_json[reason] 请求信息解析失败;return ws_resp(conn,resp_json);}//3.对于请求进行处理if (!req_json[optype].isNull() req_json[optype].asString() match_start){//开始匹配对战通过匹配模块将玩家添加到对应的匹配队列当中_mm.add(ssp-get_user());resp_json[optype] match_start;resp_json[result] true;return ws_resp(conn,resp_json);}else if(!req_json[optype].isNull() req_json[optype].asString() match_stop){// 停⽌对战匹配通过匹配模块将⽤⼾从匹配队列中移除_mm.del(ssp-get_user());resp_json[optype] match_stop;resp_json[result] true;return ws_resp(conn,resp_json);}resp_json[optype] unknow;resp_json[reason] 请求类型未知;resp_json[result] false;return ws_resp(conn, resp_json);}
游戏大厅匹配前端技术
!DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0title游戏大厅/titlelink relstylesheet href./css/common.csslink relstylesheet href./css/game_hall.css
/headbodydiv classnav网络五子棋对战游戏/div!-- 整个页面的容器元素 --div classcontainer!-- 这个 div 在 container 中是处于垂直水平居中这样的位置的 --div!-- 展示用户信息 --div idscreen/div!-- 匹配按钮 --div idmatch-button开始匹配/div/div/divscript src./js/jquery.min.js/scriptscriptvar ws_url ws:// location.host /hall;var ws_hdl null;window.onbeforeunload function () {ws_hdl.close();}//按钮有两个状态没有进行匹配的状态正在匹配中的状态var button_flag stop;//点击按钮的事件处理var be document.getElementById(match-button);be.onclick function () {if (button_flag stop) {//1. 没有进行匹配的状态下点击按钮发送对战匹配请求var req_json {optype: match_start}ws_hdl.send(JSON.stringify(req_json));} else {//2. 正在匹配中的状态下点击按钮发送停止对战匹配请求var req_json {optype: match_stop}ws_hdl.send(JSON.stringify(req_json));}}function get_user_info() {$.ajax({url: /info,type: get,success: function (res) {var info_html p 用户 res.username 积分 res.score /br 比赛场次 res.total_count 获胜场次 res.win_count /p;var screen_div document.getElementById(screen);screen_div.innerHTML info_html;ws_hdl new WebSocket(ws_url);ws_hdl.onopen ws_onopen;ws_hdl.onclose ws_onclose;ws_hdl.onerror ws_onerror;ws_hdl.onmessage ws_onmessage;},error: function (xhr) {alert(JSON.stringify(xhr));location.replace(/login.html);}})}function ws_onopen() {console.log(websocket onopen);}function ws_onclose() {console.log(websocket onopen);}function ws_onerror() {console.log(websocket onopen);}function ws_onmessage(evt) {var rsp_json JSON.parse(evt.data);if (rsp_json.result false) {alert(evt.data);location.replace(/login.html);return;}if (rsp_json[optype] hall_ready) {alert(游戏大厅连接建立成功);} else if (rsp_json[optype] match_success) {//对战匹配成功alert(对战匹配成功进入游戏房间);location.replace(/game_room.html);} else if (rsp_json[optype] match_start) {console.log(玩家已经加入匹配队列);button_flag start;be.innerHTML 匹配中....点击按钮停止匹配!;return;} else if (rsp_json[optype] match_stop) {console.log(玩家已经移除匹配队列);button_flag stop;be.innerHTML 开始匹配;return;} else {alert(evt.data);location.replace(/login.html);return;}}get_user_info();/script
/body/html ②游戏房间中进行下棋或聊天动作
首先通过通信连接获取session会话信息 然后通过session会话信息获取uid通过uid获取房间信息。将消息获取下来进行反序列化存储在Json对象中最后将Json对象交给房间管理模块让其处理下棋或聊天动作。 //进入房间进行下棋对战或聊天void wsmsg_game_room(wsserver_t::connection_ptr conn,wsserver_t::message_ptr msg){Json::Value resp_json;//1.获取session识别客户端身份session_ptr ssp get_session_by_cookie(conn);if(ssp.get()nullptr){DLOG(房间-没有找到会话信息);return;}//2.获取客⼾端房间信息room_ptr rp _rm.get_room_by_uid(ssp-get_user());if(rp.get()nullptr){resp_json[optype] unknow;resp_json[reason] 没有找到玩家的房间信息;resp_json[result] false;DLOG(房间-没有找到玩家房间信息);return ws_resp(conn, resp_json);}//3.对消息进行反序列化Json::Value req_json;std::string req_body msg-get_payload();bool ret json_util::unserialize(req_body,req_json);if(retfalse){resp_json[optype] unknow;resp_json[reason] 请求信息解析失败;resp_json[result] false;DLOG(房间-请求信息解析失败);return ws_resp(conn, resp_json);}DLOG(房间收到房间请求开始处理....);//4. 通过房间模块进⾏消息请求的处理return rp-handle_request(req_json);}
游戏房间下棋聊天动作前端技术 !DOCTYPE html
html langenheadmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0title游戏房间/titlelink relstylesheet hrefcss/common.csslink relstylesheet hrefcss/game_room.css
/headbodydiv classnav网络五子棋对战游戏/divdiv classcontainerdiv idchess_area!-- 棋盘区域, 需要基于 canvas 进行实现 --canvas idchess width450px height450px/canvas!-- 显示区域 --div idscreen 等待玩家连接中... /div/divdiv idchat_area width400px height300pxdiv idchat_showp idself_msg你好/p/brp idpeer_msg你好/p/brp idpeer_msgleihoua~/p/br/divdiv idmsg_showinput typetext idchat_inputbutton idchat_button发送/button/div/div/divscriptlet chessBoard [];let BOARD_ROW_AND_COL 15;let chess document.getElementById(chess);let context chess.getContext(2d);//获取chess控件的2d画布var ws_url ws:// location.host /room;var ws_hdl new WebSocket(ws_url);var room_info null;//用于保存房间信息 var is_me;function initGame() {initBoard();context.strokeStyle #BFBFBF;// 背景图片let logo new Image();logo.src image/sky.jpeg;logo.onload function () {// 绘制图片context.drawImage(logo, 0, 0, 450, 450);// 绘制棋盘drawChessBoard();}}function initBoard() {for (let i 0; i BOARD_ROW_AND_COL; i) {chessBoard[i] [];for (let j 0; j BOARD_ROW_AND_COL; j) {chessBoard[i][j] 0;}}}// 绘制棋盘网格线function drawChessBoard() {for (let i 0; i BOARD_ROW_AND_COL; i) {context.moveTo(15 i * 30, 15);context.lineTo(15 i * 30, 430); //横向的线条context.stroke();context.moveTo(15, 15 i * 30);context.lineTo(435, 15 i * 30); //纵向的线条context.stroke();}}//绘制棋子function oneStep(i, j, isWhite) {if (i 0 || j 0) return;context.beginPath();context.arc(15 i * 30, 15 j * 30, 13, 0, 2 * Math.PI);context.closePath();var gradient context.createRadialGradient(15 i * 30 2, 15 j * 30 - 2, 13, 15 i * 30 2, 15 j * 30 - 2, 0);// 区分黑白子if (!isWhite) {gradient.addColorStop(0, #0A0A0A);gradient.addColorStop(1, #636766);} else {gradient.addColorStop(0, #D1D1D1);gradient.addColorStop(1, #F9F9F9);}context.fillStyle gradient;context.fill();}//棋盘区域的点击事件chess.onclick function (e) {// 1. 获取下棋位置判断当前下棋操作是否正常// 1. 当前是否轮到自己走棋了// 2. 当前位置是否已经被占用// 2. 向服务器发送走棋请求if (!is_me) {alert(等待对方走棋....);return;}let x e.offsetX;let y e.offsetY;// 注意, 横坐标是列, 纵坐标是行// 这里是为了让点击操作能够对应到网格线上let col Math.floor(x / 30);let row Math.floor(y / 30);if (chessBoard[row][col] ! 0) {alert(当前位置已有棋子);return;}//oneStep(col, row, true);//向服务器发送走棋请求收到响应后再绘制棋子send_chess(row, col);}function send_chess(r, c) {var chess_info {optype: put_chess,room_id: room_info.room_id,uid: room_info.uid,row: r,col: c};ws_hdl.send(JSON.stringify(chess_info));console.log(click: JSON.stringify(chess_info));}window.onbeforeunload function () {ws_hdl.close();}ws_hdl.onopen function () {console.log(房间长连接建立成功);}ws_hdl.onclose function () {console.log(房间长连接断开);}ws_hdl.onerror function () {console.log(房间长连接出错);}function set_screen(me) {var screen_div document.getElementById(screen);if (me) {screen_div.innerHTML 轮到己方走棋...;} else {screen_div.innerHTML 轮到对方走棋...;}}ws_hdl.onmessage function (evt) {//1. 在收到room_ready之后进行房间的初始化// 1. 将房间信息保存起来var info JSON.parse(evt.data);console.log(JSON.stringify(info));if (info.optype room_ready) {room_info info;is_me room_info.uid room_info.white_id ? true : false;set_screen(is_me);initGame();} else if (info.optype put_chess) {console.log(put_chess evt.data);//2. 走棋操作// 3. 收到走棋消息进行棋子绘制if (info.result false) {alert(info.reason);return;}//当前走棋的用户id与我自己的用户id相同就是我自己走棋走棋之后就轮到对方了is_me info.uid room_info.uid ? false : true;//绘制棋子的颜色应该根据当前下棋角色的颜色确定isWhite info.uid room_info.white_id ? true : false;//绘制棋子if (info.row ! -1 info.col ! -1) {oneStep(info.col, info.row, isWhite);//设置棋盘信息chessBoard[info.row][info.col] 1;}//是否有胜利者if (info.winner 0) {return;}var screen_div document.getElementById(screen);if (room_info.uid info.winner) {screen_div.innerHTML info.reason;} else {screen_div.innerHTML 你输了;}var chess_area_div document.getElementById(chess_area);var button_div document.createElement(div);button_div.innerHTML 返回大厅;button_div.onclick function () {ws_hdl.close();location.replace(/game_hall.html);}chess_area_div.appendChild(button_div);} else if (info.optype chat) {//收到一条消息判断result如果为true则渲染一条消息到显示框中if (info.result false) {alert(info.reason);return;}var msg_div document.createElement(p);msg_div.innerHTML info.message;if (info.uid room_info.uid) {msg_div.setAttribute(id, self_msg);} else {msg_div.setAttribute(id, peer_msg);}var br_div document.createElement(br);var msg_show_div document.getElementById(chat_show);msg_show_div.appendChild(msg_div);msg_show_div.appendChild(br_div);document.getElementById(chat_input).value ;}}//3. 聊天动作// 1. 捕捉聊天输入框消息// 2. 给发送按钮添加点击事件点击俺就的时候获取到输入框消息发送给服务器var cb_div document.getElementById(chat_button);cb_div.onclick function () {var send_msg {optype: chat,room_id: room_info.room_id,uid: room_info.uid,message: document.getElementById(chat_input).value};ws_hdl.send(JSON.stringify(send_msg));}/script
/body/html
websocket连接收到消息的回调函数
获取通信连接通过通信连接获取websocket请求对象通过请求对象获取uri通过uri判断业务处理的请求。 void wsmsg_callback(websocketpp::connection_hdl hdl,wsserver_t::message_ptr msg){wsserver_t::connection_ptr conn _wssrv.get_con_from_hdl(hdl);websocketpp::http::parser::request req conn-get_request();std::string uri req.get_uri();if (uri /hall) {//建⽴了游戏⼤厅的⻓连接return wsmsg_game_hall(conn, msg);}else if (uri /room) {//建⽴了游戏房间的⻓连接return wsmsg_game_room(conn, msg);}}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/83225.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!