【在线五子棋对战】session

目录

定时器

error_code是干什么的?

Session类

Session管理类


定时器

websocketpp库提供了定时器接口set_timer

cpp 复制代码
timer_ptr set_timer(long duration, timer_handler callback);
  • duration为定时的毫秒数
  • callback为到时间时触发的定时任务
    其中,callback的类型timer_handler如下:
cpp 复制代码
using timer_handler =
    std::function<void(websocketpp::lib::error_code)>;

例如,想要在5000ms后执行一个输出任务:

cpp 复制代码
int main()
{
    websocketpp::server<websocketpp::config::asio> server;
    server.init_asio();
    server.set_timer(5000, [](const websocketpp::lib::error_code &err)
                     { std::cout << "无敌" << std::endl; });
    server.run();
    return 0;
}

error_code是干什么的?

在设置定时器后, set_timer返回一个timer_ptr 定时器对象,通过它还可以取消定时任务 (这里的取消只是取消定时 ,没有取消任务,相当于立即执行任务)

cpp 复制代码
int main()
{
    websocketpp::server<websocketpp::config::asio> server;
    server.init_asio();
    auto timer_ptr = server.set_timer(5000, [](const websocketpp::lib::error_code &err)
                     { std::cout << "无敌" << std::endl; });
                     
    timer_ptr->cancel(); // 取消定时任务
    server.run();
    return 0;
}

但这样取消后会立刻进入回调Lambda ,但此时该回调的 error_code 就不为0了,因此可以加个判断:

cpp 复制代码
int main()
{
    websocketpp::server<websocketpp::config::asio> server;
    server.init_asio();
    auto timer_ptr = server.set_timer(5000, [](const websocketpp::lib::error_code &err)
                     {  if(err) // 错误码被设置
                            return;
                        std::cout << "无敌" << std::endl; });

    timer_ptr->cancel(); // 取消定时任务
    server.run();
    return 0;
}

这样当取消定时任务后,就不会执行回调函数内的语句了

Session类

定义一个Session

cpp 复制代码
enum class Session_Status
{
    UNLOGIN,
    LOGIN
};

class Session
{
    using websocket_server = websocketpp::server<websocketpp::config::asio>;

public:
    Session(uint32_t ssid) : _ssid(ssid) { LOG(LogLv::DEBUG, "Session[%p]被创建", this); }

    ~Session() { LOG(LogLv::DEBUG, "Session[%p]被释放", this); }

    void Set_User(int uid) { _uid = uid; } // 设置该Session的用户

    void Set_Statu(Session_Status statu) { _ss_statu = statu; }; // 设置Session状态

    uint32_t Get_Ssid() { return _ssid; } // 获取 Session ID

    int Get_User() { return _uid; } // 获取 Session用户

    bool Is_Login() { return _ss_statu == Session_Status::LOGIN; } // 判断该用户是否已登录

    void Set_Timer(const websocket_server::timer_ptr &timer) { _timer = timer; } // 设置Session定时任务

    websocket_server::timer_ptr &Get_Timer() { return _timer; } // 获取定时器

private:
    uint32_t _ssid;                     // Session ID
    int _uid;                           // 用户id
    Session_Status _ss_statu;           // 用户状态 (登录 / 未登录)
    websocket_server::timer_ptr _timer; // session关联的定时器
};

Session管理类

对于多个Session,需要管理起来,因此这里要有一个 Session 管理类

其中,每个Session用智能指针管理

cpp 复制代码
using session_ptr = std::shared_ptr<Session>;

class Session_Manager
{
    using websocket_server = websocketpp::server<websocketpp::config::asio>;

public:
    Session_Manager(websocket_server *server) : _next_ssid(1), _server(server)
    {
        LOG(LogLv::DEBUG, "Session管理器初始化成功");
    }

    ~Session_Manager() { LOG(LogLv::DEBUG, "Session管理器即将被销毁"); }

    session_ptr Create_Session(uint32_t uid, Session_Status statu) // 创建session
    {
        std::lock_guard<std::mutex> lock(_mutex); // 加锁保证线程安全

        session_ptr ssp(new Session(_next_ssid));          // 创建一个Session对象
        ssp->Set_User(uid);                                // 设置该Session的用户
        ssp->Set_Statu(statu);                             // 设置该Session的状态
        _sessions.insert(std::make_pair(_next_ssid, ssp)); // 建立起ssid与Session的映射
        _next_ssid++;                                      // 下一次创建Session时就用下一个值了
        return ssp;
    }

    void Remove_Session(uint32_t ssid) // 删除session
    {
        std::lock_guard<std::mutex> lock(_mutex); // 加锁保证线程安全

        _sessions.erase(ssid);
    }

    session_ptr Get_Session_FromSsid(uint32_t ssid)
    {
        std::lock_guard<std::mutex> lock(_mutex); // 加锁保证线程安全

        auto it = _sessions.find(ssid);
        if (it == _sessions.end()) // 如果没有该session,返回空智能指针
            return session_ptr();
        return it->second;
    }

    void Set_Session_ExpireTime(uint32_t ssid, int ms) // 依赖于websocketpp的定时器完成Session生命周期管理
    // 在登录后创建Session,在指定时间无通信后删除
    {
        // 进入游戏大厅/房间时,Session永久存在
        // 退出游戏大厅/房间时,Session就要开始计时
        session_ptr ssp = Get_Session_FromSsid(ssid);
        if (ssp.get() == nullptr) // 根本没有这个Session(你只是怕了。。)
            return;

        websocket_server::timer_ptr timer = ssp->Get_Timer();
        // 1. 在Session永久存在的情况下,设置永久
        if (timer.get() == nullptr && ms == SESSION_FOREVER)
            return;
        // 2. 在Session永久存在的情况下,设置定时
        if (timer.get() == nullptr && ms != SESSION_FOREVER)
        {
            websocket_server::timer_ptr tmp_tp = // 创建一个定时删除任务
                _server->set_timer(ms, [this, ssid](const websocketpp::lib::error_code &err)
                                   { if(err) return; // 当主动取消(cancel)时,不会执行删除
                                     this->Remove_Session(ssid); });
            ssp->Set_Timer(tmp_tp); // 绑定 定时器 到 目标Session
            return;
        }
        // 3. 在Session设置定时的情况下,设置永久
        if (timer.get() != nullptr && ms == SESSION_FOREVER)
        {
            // 取消原来的定时任务
            // 取消后,其回调会被调用,并收到 operation_aborted
            timer->cancel();
            ssp->Set_Timer(websocket_server::timer_ptr()); // 将该会话的定时器清除
            return;
        }
        // 4. 在Session设置定时的情况下,重置定时
        if (timer.get() != nullptr && ms != SESSION_FOREVER)
        {
            // 删除原先的定时任务,这会导致立即执行回调,但回调函数内设置了对err的判断,不会删除映射
            timer->cancel();
            websocket_server::timer_ptr tmp_tp = // 创建一个新定时删除任务
                _server->set_timer(ms, [this, ssid](const websocketpp::lib::error_code &err)
                                   { if(err) return; // 当主动取消(cancel)时,不会执行删除
                                     this->Remove_Session(ssid); });
            ssp->Set_Timer(tmp_tp); // 绑定 定时器 到 目标Session
        }
        return;
    }

private:
    uint32_t _next_ssid;                                 // 下一个创建的session的id
    std::mutex _mutex;                                   // 保证线程安全
    std::unordered_map<uint32_t, session_ptr> _sessions; // session id 与 session会话指针的映射
    websocket_server *_server;                           // 用于创建定时器任务
};
相关推荐
ESDWAN1 小时前
跨境网络频繁掉线怎么排查?从企业内网到 SD-WAN 链路的故障诊断
开发语言·网络·php
资深电气设计1 小时前
数据中心低压盘柜选型逻辑解析:ABB技术体系的参考价值
网络·创业创新·业界资讯
牧羊人.3331 小时前
动手学深度学习 07|Resnet网络与迁移学习
网络·人工智能·深度学习·神经网络·算法·cnn·迁移学习
北京中科新远科技1 小时前
AI网络设备兼容性验收实战:交换机、网卡、线缆与光模块逐层检查
网络
集智飞行2 小时前
解决mavros2 ros2版本cpu占用高的问题
java·服务器·前端
Java后端的Ai之路2 小时前
昇腾NPU显存管理避坑指南:从npu-smi输出精准识别空闲卡的底层逻辑与实战
服务器·网络·数据库·npu·大模型服务
小宋10212 小时前
Agent轨迹级评测实战:工具选择、预算超限与回归门禁
android·网络·人工智能·回归
小码哥0683 小时前
搭建短剧系统|海外短剧:从需求到上线的指南
网络·数据库·音视频·短剧小程序·短剧系统·短剧开发·短剧后台