2.7.C++项目:网络版五子棋对战之session模块的设计

news2024/12/26 0:22:39

文章目录

  • 零、前置
  • 一、意义
  • 二、功能
  • 三、管理
  • 四、框架
  • 五、完整代码

零、前置

在WEB开发中,HTTP协议是⼀种无状态短链接的协议,这就导致⼀个客户端连接到服务器上之后,服务器不知道当前的连接对应的是哪个用户,也不知道客户端是否登录成功,这时候为客户端提所有服务是不合理的。

在这里插入图片描述

因此,服务器为每个用户浏览器创建⼀个会话对象(session对象)。
注意:⼀个浏览器独占⼀个session对象(默认情况下)。因此,在需要保护用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,识别该连接对应的用户,并为用户提供服务。
在这里插入图片描述

一、意义

保存客户端的用户状态信息。

二、功能

  1. 有自己的表示:ssid
  2. 用户的状态信息

三、管理

session管理:
// 1. 创建session
// 2. 为session设置过期时间
// 3. 获取session
// 4. 销毁session(过期被自动销毁)

四、框架

#ifndef __M_SS_H__
#define __M_SS_H__
#include "util.hpp"
#include <unordered_map>
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>

typedef enum {UNLOGIN, LOGIN} ss_statu;
class session {
    private:
        uint64_t _ssid; //标识符
        uint64_t _uid; //session对应的用户ID
        ss_statu _statu; //用户状态:未登录,已登录
        wsserver_t::timer_ptr _tp; //session关联的定时器
    public:
        session(uint64_t ssid): _ssid(ssid) { 
            DLOG("SESSION %p 被创建!!", this); 
        }
        ~session() { 
            DLOG("SESSION %p 被释放!!", this); 
        }
        uint64_t ssid() { 
            return _ssid; 
        }
        void set_statu(ss_statu statu) { 
            _statu = statu; 
        }
        void set_user(uint64_t uid) { 
            _uid = uid; 
        }
        uint64_t get_user() { 
            return _uid;
        }
        bool is_login() { 
            return (_statu == LOGIN); 
        }
        void set_timer(const wsserver_t::timer_ptr &tp) {
             _tp = tp;
        }
        wsserver_t::timer_ptr& get_timer() { 
            return _tp; 
        }
};

五、完整代码

// session模块:保存客户端的用户状态信息
// 1. 有自己的表示:ssid
// 2. 用户的状态信息

// session管理:
// 1. 创建session
// 2. 为session设置过期时间
// 3. 获取session
// 4. 销毁session(过期被自动销毁)

// websocket库中定时器的使用!
// 定时任务取消会导致定时任务立刻被执行!

#ifndef __M_SS_H__
#define __M_SS_H__
#include "util.hpp"
#include <unordered_map>
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>

typedef enum {UNLOGIN, LOGIN} ss_statu;
class session {
    private:
        uint64_t _ssid; //标识符
        uint64_t _uid; //session对应的用户ID
        ss_statu _statu; //用户状态:未登录,已登录
        wsserver_t::timer_ptr _tp; //session关联的定时器
    public:
        session(uint64_t ssid): _ssid(ssid) { 
            DLOG("SESSION %p 被创建!!", this); 
        }
        ~session() { 
            DLOG("SESSION %p 被释放!!", this); 
        }
        uint64_t ssid() { 
            return _ssid; 
        }
        void set_statu(ss_statu statu) { 
            _statu = statu; 
        }
        void set_user(uint64_t uid) { 
            _uid = uid; 
        }
        uint64_t get_user() { 
            return _uid;
        }
        bool is_login() { 
            return (_statu == LOGIN); 
        }
        void set_timer(const wsserver_t::timer_ptr &tp) {
             _tp = tp;
        }
        wsserver_t::timer_ptr& get_timer() { 
            return _tp; 
        }
};

#define SESSION_TIMEOUT 30000
#define SESSION_FOREVER -1
using session_ptr = std::shared_ptr<session>;
// 管理的数据
// 1.ssid的计数器
// 2.互斥锁
// 3.管理器 unordered_map<ssid,session_ptr>
// 4.websocket 的 server 对象 —— 用于添加定时任务
class session_manager {
    private:
        uint64_t _next_ssid;
        std::mutex _mutex;
        std::unordered_map<uint64_t, session_ptr> _session;
        wsserver_t *_server;
    public:
        session_manager(wsserver_t *srv): _next_ssid(1), _server(srv){
            DLOG("session管理器初始化完毕!");
        }
        ~session_manager() { DLOG("session管理器即将销毁!"); }
        // 创建一个session
        session_ptr create_session(uint64_t uid, ss_statu statu) {
            std::unique_lock<std::mutex> lock(_mutex);
            session_ptr ssp(new session(_next_ssid));
            ssp->set_statu(statu);
            ssp->set_user(uid);
            _session.insert(std::make_pair(_next_ssid, ssp));
            _next_ssid++;
            return ssp;
        }

        // 添加一个已有的session
        void append_session(const session_ptr &ssp) {
            std::unique_lock<std::mutex> lock(_mutex);
            _session.insert(std::make_pair(ssp->ssid(), ssp));
        }
        // 获取一个session
        session_ptr get_session_by_ssid(uint64_t ssid) {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _session.find(ssid);
            if (it == _session.end()) {
                return session_ptr();
            }
            return it->second;
        }
        void remove_session(uint64_t ssid) {
            std::unique_lock<std::mutex> lock(_mutex);
             _session.erase(ssid);
        }
        // 定时删除任务
        void set_session_expire_time(uint64_t ssid, int ms) {
            // 依赖于websocketpp的定时器来完成session生命周期的管理。
            // 登录之后,创建session,session需要在指定时间无通信后删除
            // 但是进入游戏大厅,或者游戏房间,这个session就应该永久存在
            // 等到退出游戏大厅,或者游戏房间,这个session应该被重新设置为临时,在长时间无通信后被删除

            // 在http通信的时候(登录,注册) session 应该具备生命周期,指定时间无通信后删除!
            // 在客户端建立websocket长链结构,session应该是永久存在的!
            // 登录之后,创建session session需要在指定时间后无通信就删除
            // 但是在进入游戏大厅,或者游戏房间,这个session就应该永久存在
            // 但是在推出游戏大厅或者游戏房间,这个session就应该被重新设置为临时的,在长时间无通信后删除!
            session_ptr ssp = get_session_by_ssid(ssid);
            if (ssp.get() == nullptr) {
                return;
            }
            wsserver_t::timer_ptr tp = ssp->get_timer();
    
             // 1. 在session永久存在的情况下,设置永久存在
            if (tp.get() == nullptr && ms == SESSION_FOREVER) {
                // 1. 在session永久存在的情况下,设置永久存在
                return ;
             // 2. 在session永久存在的情况下,设置指定时间之后被删除的定时任务
            }
            else if (tp.get() == nullptr && ms != SESSION_FOREVER) {
                 wsserver_t::timer_ptr tmp_tp = _server->set_timer(ms, 
                    std::bind(&session_manager::remove_session, this, ssid));
                ssp->set_timer(tmp_tp);
            }
             // 3. 在session设置了定时删除的情况下,将session设置为永久存在
            else if (tp.get() != nullptr && ms == SESSION_FOREVER) {
                // 删除定时任务--- stready_timer删除定时任务会导致任务直接被执行
                tp->cancel();//因为这个取消定时任务并不是立即取消的
                //因此重新给session管理器中,添加一个session信息, 且添加的时候需要使用定时器,而不是立即添加
                ssp->set_timer(wsserver_t::timer_ptr());//将session关联的定时器设置为空
                // 可能在添加之后又被删除
                _server->set_timer(0, std::bind(&session_manager::append_session, this, ssp));
            }
             // 4. 在session设置了定时删除的情况下,将session重置删除时间
            else {
                tp->cancel();//因为这个取消定时任务并不是立即取消的
                ssp->set_timer(wsserver_t::timer_ptr());
                _server->set_timer(0, std::bind(&session_manager::append_session, this, ssp));
                
                 //重新给session添加定时销毁任务
                wsserver_t::timer_ptr tmp_tp  = _server->set_timer(ms,std::bind(&session_manager::remove_session, this, ssp->ssid()));
                //重新设置session关联的定时器
                ssp->set_timer(tmp_tp);
            }
        }
};

#endif

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

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

相关文章

24李永乐模拟6套卷中的一道定积分定义+真题改编题

大概率是武忠祥老师出的一道题&#xff0c;同时考察了数形结合&#xff0c;定积分换元&#xff0c;无穷级数表示&#xff0c;广义积分中值定理&#xff0c;定积分定义的一道真题改编好题。 第二问用第一问结论&#xff0c;区间再现一步秒杀&#xff0c;颇有真题风范。

找不到msvcp100.dll解决教程

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp100.dll丢失”。这个错误通常会导致某些应用程序无法正常运行。为了解决这个问题&#xff0c;本文将介绍四个修复msvcp100.dll丢失的方法&#xff0c;帮助读者快速恢复计算机的正常运…

【c++】运算符重载实例

重载自增自减运算符 Intger num(2); num; num;对自增运算符的重载要区分前置和后置。在重载之前需要思考一个问题&#xff0c;num是返回一个临时变量还是num对象的本体。 为了解决这个问题可以考虑实现一个Inc_()函数和_Inc()函数分别模仿后置和前置的行为 Integer Inc_(){i…

Calibre拾遗:FDI (Foreign Database Interface)系统简介

Calibre是强大的GDS处理工具&#xff0c;包括查看&#xff0c;验证&#xff0c;分析等操作&#xff0c;操作由浅入深&#xff0c;除过手动编辑GDS的不是很灵活外&#xff0c;其他各种命令和操作策略&#xff0c;都是远&#xff08;遥&#xff09;远&#xff08;遥&#xff09;走…

使用create-vue创建项目

认识create-vue create-vue是Vue官方新的脚手架工具&#xff0c;底层切换到了vite&#xff08;下一代构建工具&#xff09;&#xff0c;为开发提供极速响应。 使用create-vue创建项目 1.前提环境条件 已安装16.0或更高版本的Node.js node -v 2.创建一个Vue应用 npm init…

Monocular arbitrary moving object discovery and segmentation 论文阅读

基本信息 题目&#xff1a;Monocular Arbitrary Moving Object Discovery and Segmentation 作者&#xff1a; 来源&#xff1a;BMVC 时间&#xff1a;2021 代码地址&#xff1a;https://github.com/michalneoral/Raptor Abstract 我们提出了一种发现和分割场景中独立移动的…

[算法训练营] 回溯算法专题(一)

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的…

Linux系列讲解 —— VIM配置与美化

目录 1. Vim基本配置1.1 配置文件1.2 基本配置 2. 插件管理器Vundle2.1 下载Vundle2.2 在vimrc中添加Vundle的配置 3. Vundle的使用3.1 安装插件3.2 卸载插件 1. Vim基本配置 1.1 配置文件 vim的配置文件有两处&#xff0c;请根据实际情况选择修改哪个。 (1) 全局配置文件&am…

电子元器件管理系统 JAVA语言开发

目录 一、系统介绍 二、系统下载 三、系统截图 一、系统介绍 基于VueSpringBootMySQL的电子元器件管理系统包含元器件单位模块、元器件仓库模块、元器供应商模块、元器件品类模块、元器件明细模块、元器件采购模块、元器件采购审核模块、元器件领用模块、学生元器件申请模块…

前端AJAX入门到实战,学习前端框架前必会的(ajax+node.js+webpack+git)(二)

阳光总在风雨后&#xff0c;请相信有彩虹。 案例 - 图书管理 bootstrap弹框 需求&#xff0c;点击添加按钮&#xff0c;没有离开当前页面&#xff0c;在当前页面弹出弹框&#xff08;弹窗&#xff09; 先学着实现一个简单的弹框&#xff0c;如下图右下角 bootstrap有两种方式…

openGauss学习笔记-108 openGauss 数据库管理-管理用户及权限-用户

文章目录 openGauss学习笔记-108 openGauss 数据库管理-管理用户及权限-用户108.1 创建、修改和删除用户108.2 私有用户108.3 永久用户108.4 用户认证优先规则 openGauss学习笔记-108 openGauss 数据库管理-管理用户及权限-用户 使用CREATE USER和ALTER USER可以创建和管理数据…

解决虚拟机联网问题

虚拟机开机后发现右上角缺少联网标志(下面有正常联网标志)&#xff0c;这样就是连不上网的 不信你可以打开Ubuntu里面的浏览器或ping www.baidu.com 1.编辑虚拟机设置-->网络适配器-->如图所示 2.选择编辑-->虚拟网络编辑器 3.更改设置 4此处可以选择还原默认设置&am…

【JAVA学习笔记】42 - 内部类(难点,重点)

项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter10/src/com/yinhai/innerclass_ 一、基本介绍 一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成…

【蓝桥每日一题]-动态规划 (保姆级教程 篇12)#照相排列

这次是动态规划最后一期了&#xff0c;感谢大家一直以来的观看&#xff0c;以后就进入新的篇章了 目录 题目&#xff1a;照相排列 思路&#xff1a; 题目&#xff1a;照相排列 思路&#xff1a; 首先记录状态f[a][b][c][d][e]表示每排如此人数下对应的方案数&#xff0c;然…

java中按行读取文件内容

java中按行来读取文件内容&#xff0c;一般对文件也是又要求的&#xff0c;比如文件编码utf-8&#xff0c;内容是按行可读&#xff0c;而不是一堆字节码。这类文件&#xff0c;我们按行读取&#xff0c;主要是方便快速查看内容&#xff0c;并且用这些内容来作别的用途&#xff…

FileUpload控件上传文件时出现 不支持给定路径的格式.的解决方法

正常代码&#xff0c;部署到server 2012时&#xff0c;在上传音频mp3文件时&#xff0c;显示错误“不支持给定路径的格式”&#xff0c;上传控件使用FileUpload控件&#xff1a; 因为程序之前是正常的&#xff0c;因此应该不是程序的问题。 上传时&#xff0c;发现在选择文件时…

F28335-可移植新建工程模板-基于bitfield

文章目录 前言步骤新建工程工程管理拷贝底层文件 添加测试函数编写main.c测试函数 前言 实验要求利用28335芯片&#xff0c;重新学习一下DSP28335&#xff0c;并做个记录。 值得一提的是&#xff0c;28335只能用寄存器开发&#xff0c;而不能用库函数开发&#xff0c;相应的也…

LDAP注入漏洞

1、LDAP 注入 LDAP (Light Directory Access Portocol) 是基于X.500标准的轻量级目录访问协议&#xff0c;提供访问目录数据库方法的服务和协议&#xff0c;常用于与目录数据库组成目录服务。其中目录是一个为查询、浏览和搜索而优化的专业分布式数据库&#xff0c;它呈树状结…

Java学习 1.初识Java

1.类名 当这个类被public修饰时 class后的名字 类名必须和文件名相同 public class 类名(文件名); 2.main函数 方法一定是包含在类之中的 3.类里面是函数/方法 由返回值、方法名、参数列表组合而成,方法中可以定义变量&#xff0c;方法体 4.一个文件中可以有多个类 我们建…

【管理运筹学】第 10 章 | 排队论(3,标准的 M/M/1 排队系统)

文章目录 引言一、模型特征及分析二、系统指标1. 在系统中的平均顾客数&#xff08;队长的期望&#xff09;2. 在队列中的平均顾客数&#xff08;队列长的期望&#xff09;3. 在系统中顾客平均逗留时间4. 在队列中顾客的平均等待时间 写在最后 引言 前两篇文章&#xff0c;分别…