基于websocket的多用户网页五子棋(八)

一.前期回顾

对于前面内容不太了解的,可以去看一看下面的文章:

https://blog.csdn.net/weixin_60668256/article/details/152661096?fromshare=blogdetail&sharetype=blogdetail&sharerId=152661096&sharerefer=PC&sharesource=weixin_60668256&sharefrom=from_link

二.游戏大厅长连接的建立

cpp 复制代码
void wsopen_callback(websocketpp::connection_hdl hdl)
        {

        }
cpp 复制代码
void ws_resp(wsserver_t::connection_ptr conn,Json::Value& resp)
        {
            std::string body;
            json_util::serialize(resp,body);
            conn->send(body);
        }

        void weopen_game_hall(wsserver_t::connection_ptr conn)
        {
            //游戏大厅长连接建立成功
            //1.登录验证 -- 判断当前客户端是否以及成功登录

            Json::Value err_resp;
            std::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;
                return ws_resp(conn,err_resp);
            }
            std::string ssid_str;
            bool ret = get_cookie_val(cookie_str,"SSID",ssid_str);
            if(ret == false)
            {
                err_resp["optype"] = "hall_ready";
                err_resp["reason"] = "找不到ssid信息,请重新登录";
                err_resp["result"] = false;
                return ws_resp(conn,err_resp);
            }
            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;
                return ws_resp(conn,err_resp);
            }
            //2.判定当前客户端是否重复登录
            if(_om.is_in_game_hall(ssp->get_user()) || _om.is_in_game_hall(ssp->get_user()))
            {
                err_resp["optype"] = "hall_ready";
                err_resp["reason"] = "玩家重复登录!";
                err_resp["result"] = false;
                return ws_resp(conn,err_resp);
            }
            //3.将当前客户端以及连接加入到游戏大厅
            _om.enter_game_hall(ssp->get_user(),conn);
            //4.给客户端响应长连接的游戏大厅连接成功
            Json::Value resp_json;
            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);

        }

        void weopen_game_room(wsserver_t::connection_ptr conn)
        {

        }

        void wsopen_callback(websocketpp::connection_hdl hdl)
        {
            //websocket长连接建立成功的回调函数
            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 weopen_game_hall(conn);
            }
            else if(uri == "/room")
            {
                //建立游戏房间的长连接
                return weopen_game_room(conn);
            }
        }
html 复制代码
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 onclose");
        }
        function ws_onerror() {
            console.log("websocket onerror");
        }

目前还没有实现游戏房间内的长连接,我们先进行长连接移除的函数实现

三.游戏大厅长连接的删除

cpp 复制代码
void wsclose_game_hall(wsserver_t::connection_ptr conn)
        {
            //游戏大厅的长连接断开
            Json::Value err_resp;
            std::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;
                return ws_resp(conn,err_resp);
            }
            std::string ssid_str;
            bool ret = get_cookie_val(cookie_str,"SSID",ssid_str);
            if(ret == false)
            {
                err_resp["optype"] = "hall_ready";
                err_resp["reason"] = "找不到ssid信息,请重新登录";
                err_resp["result"] = false;
                return ws_resp(conn,err_resp);
            }
            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;
                return ws_resp(conn,err_resp);
            }
            //1.将玩家从游戏大厅移除
            _om.exit_game_hall(ssp->get_user());
            //2.将session恢复生命周期的管理
            _sm.set_session_expire_time(ssp->ssid(),SESSION_TIMEOUT);
        }
        void wsclose_game_room(wsserver_t::connection_ptr conn)
        {
            //游戏房间的长连接断开
        }
        void wsclose_callback(websocketpp::connection_hdl hdl)
        {
            //1.websocket连接断开前的处理
            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);
            }
        }
html 复制代码
window.onbeforeunload = function() {
            ws_hdl.close();
        }

房间内同样还是没有进行完成

四.游戏大厅内消息处理

实现按钮点击发送消息到后台服务器

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>游戏大厅</title>
    <link rel="stylesheet" href="./css/common.css">
    <link rel="stylesheet" href="./css/game_hall.css">
</head>
<body>
    <div class="nav">网络五子棋对战游戏</div>
    <!-- 整个页面的容器元素 -->
    <div class="container">
        <!-- 这个 div 在 container 中是处于垂直水平居中这样的位置的 -->
        <div>
            <!-- 展示用户信息 -->
            <div id="screen"></div>
            <!-- 匹配按钮 -->
            <div id="match-button">开始匹配</div>
        </div>
    </div>

    <script src="./js/jquery.min.js"></script>
    <script>
        var 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 onclose");
        }
        function ws_onerror() {
            console.log("websocket onerror");
        }
        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>
cpp 复制代码
void ws_resp(wsserver_t::connection_ptr conn,Json::Value& resp)
        {
            std::string body;
            json_util::serialize(resp,body);
            conn->send(body);
        } 

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;
            }
            std::string req_body = msg->get_payload();
            Json::Value req_json;
            bool ret = json_util::unserialize(req_body,req_json);
            if(ret == false)
            {
                resp_json["result"] = false;
                resp_json["reason"] = "请求信息解析失败";
                return ws_resp(conn,resp_json);
            }
            //2.对于请求进行处理
            if(!req_json["optype"].isNull() &&req_json["optype"].asString() == "match_start")
            {
                //1.开始对战匹配 : 通过匹配模块,将用户添加到匹配队列中
                _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")
            {
                //2.停止对战匹配 : 通过匹配模块,将用户从匹配队列中移除
                _mm.del(ssp->get_user());
                resp_json["optype"] = "match_stop";
                resp_json["result"] = true;
                return ws_resp(conn,resp_json);
            }
            //3.给客户端响应
            resp_json["optype"] = "unkonw";
            resp_json["result"] = false;
            return ws_resp(conn,resp_json);
        }
        void wsmsg_game_room(wsserver_t::connection_ptr conn,wsserver_t::message_ptr msg)
        {
            //
        }
        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);
            }
        }

五.目前效果演示(还没写房间内的游戏逻辑)

不要在同一个浏览器上进行登录两个用户session会有影响

两个全部匹配成功

目前房间内还没写,所以是这样的

相关推荐
San304 小时前
深入理解 JavaScript 函数:从基础到高阶应用
前端·javascript·node.js
ttyyttemo4 小时前
Column,rememberScrollState,记住滚动位置
前端
ajassi20004 小时前
开源 C++ QT QML 开发(十二)通讯--TCP客户端
c++·qt·开源
Elastic 中国社区官方博客4 小时前
Elasticsearch:使用推理端点及语义搜索演示
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
馨谙5 小时前
Linux中权限系统
linux·运维·服务器
进击的圆儿5 小时前
【学习笔记05】C++11新特性学习总结(下)
c++·笔记·学习
Jayden_Ruan5 小时前
C++十进制转二进制
数据结构·c++·算法
芒果茶叶5 小时前
并行SSR,SSR并行加载
前端·javascript·架构
武子康5 小时前
Java-143 深入浅出 MongoDB NoSQL:MongoDB、Redis、HBase、Neo4j应用场景与对比
java·数据库·redis·mongodb·性能优化·nosql·hbase