基于skynet框架的一种游戏服登录模块设计
基于skynet框架的一种游戏服登录模块设计
- 核心设计点
- 详细步骤
- 系统架构概览
- 核心登录流程
- 一些关键点
- 1. 客户端发起登录请求
- 2. Token验证流程
- 3. 顶号处理机制
- 4. 用户数据加载
- 5. 分布式节点分配
- 6. 首次登录处理
- 7. 在线状态管理
- 完整登录时序图
- 设计优势
核心逻辑依赖2个服务模块,中心服务(center)和登录服务(login)
核心设计点
1. 分布式架构:多个中心服务(center)通过取模分配用户,每个中心服务负责一部分用户
2. Token验证:使用Redis存储和验证token
3. 顶号处理:当一个账号在别处登录时,会将前一个登录踢下线
4. 离线处理:玩家下线时,会清理在线状态并通知相关房间
5. 首次登录奖励:玩家第一次登录时,会发放初始货币奖励
6. 登录状态管理:使用记录来防止同时登录
详细步骤
步骤1:客户端发送登录请求(C_LOGIN_GAME)
步骤2:登录服务(login)处理请求,进行初步参数检查
步骤3:调用中心服务(center)进行token验证和登录
步骤4:中心服务(center)处理登录请求,包括顶号处理
步骤5:创建代理服务(agent)并注册到网关(gate)
步骤6:返回登录结果给客户端
系统架构概览
客户端 --> 网关 --> 登录服务 --> 中心服务(验证token、顶号) --> 创建代理服务 --> 注册到网关 --> 返回登录结果
客户端 → Gateway → Login服务 → Center服务 → 数据库/Redis↓Agent服务(玩家实例)
核心登录流程
1. 初步检查:
- 检查uid和token是否存在,uid是否大于0,token是否非空
- 检查玩家是否正在登录中,可以使用skynet.uniqueservice定义节点内的唯一服务(例如login_datad,通过login_datad服务进行记录,防止重复登录)
2. 生成一个key(用于后续通信的密钥)
3. 调用中心服务(center)的login方法进行登录:
- 参数包括节点名、fd、网关地址、key、token等
4. 中心服务(center_login.lua)的dispatch.login方法:
- 检查是否正在登录(logining_record记录),防止重复登录
- 根据uid获取用户信息(env.get_user),如果用户不存在则返回失败
- 从Redis获取最新的token,与传入的token比较,如果不一致则返回失败
- 如果用户已经登录(user.login_info存在且在线),则踢掉之前的连接(kick_user)
- 更新用户的登录信息(env.user_login)
5. 如果中心服务返回成功,则继续在登录服务中创建代理服务(agent):
- 调用libclientagent.login创建agent服务
6. 获取客户端IP
7. 调用中心服务的register方法,将agent信息注册到中心服务:
- 在中心服务中,记录agent信息,并将用户设置为在线(user_online)
- 如果是首次登录,发放初始奖励
8. 将agent注册到网关(gate),这样后续的消息就可以直接转发到agent
9. 整理玩家信息,返回给客户端(S_LOGIN_GAME)
10. 清理登录记录,并触发一些后续操作(如每日奖励等)
一些关键点
1. 客户端发起登录请求
- 检查uid和token是否存在,uid是否大于0,token是否非空
-- login.lua
function forward.C_LOGIN_GAME(fd, msg, source)local uid = msg.uidlocal token = msg.token...
关键参数:
- uid: 用户ID
- token: 登录令牌
2. Token验证流程
-- center_login.lua
function dispatch.login(uid, data)local user_token = libredisproxy.get_token(uid)if (not user_token) or user_token ~= token thenlog.error("%d token auth fail %s, %s", uid, token, user_token)return falseend
Token管理:
- Token存储在Redis中
- 每次登录重新从Redis获取最新token
- Token不匹配立即拒绝登录
3. 顶号处理机制
踢号流程:
- 发送踢下线协议给客户端
- 调用gateway的kick接口断开连接
- 清理在线状态记录
4. 用户数据加载
数据分层:
- Redis: Token等临时数据
- MongoDB: 玩家基础数据
- 内存缓存: 活跃玩家数据
5. 分布式节点分配
负载均衡:
- 基于UID取模分配到不同Center节点
- 每个Center服务管理一部分用户
6. 首次登录处理
首次登录特征:
- 检查logingametime字段
- 发放初始货币奖励
- 初始化账户数据
7. 在线状态管理
在线用户池:
- 使用对象池管理在线用户记录
- 记录agent服务地址和节点信息
- 支持快速查找在线用户
完整登录时序图
常规登录流程:
- 客户端发送C_LOGIN_GAME消息到网关,网关转发到登录服务
- 登录服务检查参数,生成key,并调用中心服务的login方法
- 中心服务检查token,如果token无效则返回错误
- 如果token有效,检查是否已经在线,如果在线则踢下线
- 更新用户登录信息,返回成功
- 登录服务创建代理服务(agent)
- 登录服务调用中心服务的register方法,注册agent信息,中心服务将用户状态设置为在线
- 登录服务将agent注册到网关,使得后续消息直接路由到agent
- 登录服务返回S_LOGIN_GAME消息给客户端,登录成功
- 客户端与代理服务开始通信
顶号流程:
11. 用户A在设备1登录,中心服务记录其登录信息(包括agent、fd等)
12. 用户A在设备2登录,中心服务发现已经在线,则调用kick_user踢掉设备1
13. kick_user会向设备1发送S_KICK_LOGOUT消息,并关闭设备1的连接
14. 设备1收到踢下线消息,断开连接
15. 设备2完成登录
离线流程:
16. 用户正常下线:客户端发送 logout 消息,经过agent调用中心服务的logout,清理在线状态
17. 用户异常断开:网关检测到连接断开,会调用agent的kick方法,agent再调用中心服务的logout
设计优势
1. 安全设计
- Token验证: 每次登录重新验证
- 防重复登录: 分布式锁机制
- 顶号保护: 强制踢出前一个会话
2. 性能优化
- 数据缓存: 活跃用户内存缓存
- 连接池: 在线用户对象池
- 分布式: 用户按节点分散
3. 状态一致性
- 登录状态原子操作
- 失败时资源清理
- 离线时状态同步