巢湖市建设工程网站某公司网站建设策划书

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,一经查实,立即删除!

相关文章

网站配色设计郑州做网站 熊掌号

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

个人网站规划书成年男女做羞羞视频网站

1.jsonp,原理利用script的src属性(像img,iframe等有src属性的都支持跨域)引入js文件,并在引入成功后调用回调函数,数据通过参数的形式传过来。 例: 2.window.name 3.document.domain 4.h5的方法:window.postMessage 5.flash 6.COR…

dede 后台 不能保存网站名称wordpress my02visitors

1. Java中有哪些主要的集合接口? 答案:Java中主要的集合接口有Collection、List、Set、Queue和Map。 2. 请解释List和Set之间的主要区别。 答案:List和Set的主要区别在于元素的顺序和唯一性。List是有序的集合,允许存储重复的元…

物流wap网站模板wordpress 火

🤡博客主页:醉竺 🥰本文专栏:《C语言深度解剖》 😻欢迎关注:感谢大家的点赞评论关注,祝您学有所成! ✨✨💜💛想要学习更多C语言深度解剖点击专栏链接查看&…

郑州市建网站wordpress页面 文章列表

在使用esp32 idf例程中的tcp_server和tcp_client通信测试时发现, 在tcp_server端,接收到一帧数据之后必须马上回复至少一个字节,才能保证每帧数据不粘包, 如果不回复操作,300ms以内的通信时延会导致tcp严重粘包&…

网站换行代码上海哪家网站建设公司好

设计原则 封装、继承、多态、抽象分别可以解决哪些编程问题 封装:也叫做信息隐藏或数据保护访问。数据 通过暴露有限的访问接口,授权外部仅能通过类提供接口访问,对内的类private私有化属性,通过封装简化操作,让用户更…

企业做淘宝网站需要多少钱为什么不建议学电子商务?

一、单选 共40题 (共计40分) 第1题 (1.0分) 题号:7098 难度:中 第1章 下列叙述中正确的是 A:一个算法的空间复杂度大,则其时间复杂度也必定大 B:一个算法的空间复杂度大,则其时间复杂度必定小 C:一个…

婚纱网站建设 最开始中油六建公司官网

相关代码gitee自取: C语言学习日记: 加油努力 (gitee.com) 接上期: 学C的第三十四天【程序环境和预处理】_高高的胖子的博客-CSDN博客 1 . 算法效率 (1). 什么是数据结构: 数据结构(Data Structure)是计算机存储、…

邵阳红网站网站整体设计流程

YB4051H 300mA 单电池锂离子电池充电器0.1 mA 终端,45nA 电池漏电流 概述: YB4051系列设备是高度集成的 Li-lon 和 Li-Pol 线性充电器,针对便携式应用的小容量电池。它是一个完整的恒流/恒压线性充电器。不需要外部感应电阻,由于…

民族团结 网站建设平台广告推广

企业想要管理销售,可以选择CRM系统;企业想要优化业务流程,可以选择CRM系统;企业想要提高收入,可以选择CRM系统。下面来说说,CRM是什么?六种常见CRM系统类型对比。 什么是CRM? CRM是…

苏州模板网站专业设计什么是网站推广?

WebBenchmark是一款基于开源通讯组件Beetlex扩展的Webapi管理和性能测试工具,在传统工具中一般管理工具缺乏性能压测能力或有性能测试的缺少管理功能;WebBenchmark的设计目标是就管理和性能压测能力同时具备。接下来介绍一下工具的功能和使用&#xff1a…

商务网站创建方案江苏省住房和城乡建设厅政务网站

导读:在我国,出租车行业是八十年代初兴起的一项新兴行业,随着出租车的产生,计价器也就应运而生。但当时在全国没有一家企业能够生产,因而那个时期的计价器是由台湾引进。台湾是计价器的主要生产场地,目前全…

怎么做网站logo国内在线免费服务器

全世界只有3.14 % 的人关注了数据与算法之美在我的后台咨询者当中,女生向我咨询最多的问题就是:女生转行IT有什么困难?是不是很多IT企业都不要女生啊?女生的逻辑不如男生,是不是学不好编程?等等。1以上的所…

桂林网站设计wordpress 添加头像

作品展示: 背景需求: 1、以前做过一份比大小的题目 【教学类-05-01】20211018 Python VSC 大班 数字比大小(> <)_vsc比较3位数大小-CSDN博客文章浏览阅读674次。【教学类-05-01】20211018 Python VSC 大班…

艺术网站建设哈尔滨网站建设服务

1.包装类 1)包装类为基本数据类型提供了相应的引用数据类型。(基本数据类型-包装类)btye-Byte,char-Character,short-Short,float-Floatint-Integer,double-Double,long-Long,boolean-Boolean 2)通过包装类的构造器来实现吧基本数据类型包装成…

安装网站提示dir互联网开发是什么意思

redis在Windows下设置静默启动 下载windows版redis,解压cmd命令行有窗口启动(这种启动方式,这个界面就不能关闭才会生效 注册成为服务,设置成开机启动或者手动启动(静默启动)清除缓存本地清除,直接打开redis-cli.exe本地远程连接清除缓存 下载…

北京朝阳建站优化广东网页空间租赁

1.2004年,不知道大家对这个时间有没有感觉,那几年我正在读高中,韩寒的《三重门》席卷校园,同样还有郭敬明的《夏至未至》。那时候的我,还挣扎在温饱阶段,我每天吃饭的时候都想上食堂的三楼吃风味&#xff0…

开启WordPress多站点功能上海公司网站制作价格

好文推荐: 2.5万字详解23种设计模式 基于Netty搭建websocket集群实现服务器消息推送 2.5万字讲解DDD领域驱动设计 文章目录 一、延时队列定义二、应用场景三、技术实现方案:1. Redis2. Kafka3. RabbitMQ4. RocketMQ 四、Kafka延时队列背景五、Kafka延时队…

中国建设行业峰会网站建设asp网站视频教程

编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果这个过程 结果为 1&#xff0c…

江门网站定制多少钱店铺推广策略

response.text() 功能:Sanic 返回纯文本内容给浏览器。作为一个完整功能的web网站,一般是不会返回纯文本内容的,特殊情况下可选择使用本函数。response.text() 语法def text(body,status200, headersNone,content_type"text/plain;chars…