2.聊天系统Gate服设计

2. 聊天系统 Gate 服设计


2.1 知识点

设计思路

Gate 服务器承担所有客户端连接的入口,专注会话管理鉴权多后端路由,把业务逻辑(Chat/Map)和网络协议彻底分离。

  • 会话管理:维护 Session 生命周期、心跳与断线重连;通过 Flag 组件绑定用户身份。(此篇暂时只专注于Gate与聊天相关的实现)
  • 路由转发:基于 RouteComponent 的 SceneType → UnitRuntimeId 映射,透明转发消息到 Chat 或 Map。
  • 统一入口:所有客户端消息仅进 Gate,不直接暴露后端 Chat,实现安全隔离与流量限控。
  • 多后端协同:登录时通知 Chat 与 Map 上线、下线时统一广播通知,保证各服状态一致。

这样的设计使后端 Chat/Map 只需关注业务逻辑,无需直接处理网络;Gate 则专注高并发连接与路由中转,可独立横向扩展。

Gate 服主要组件

classDiagram
  class GateScene {
    +Start()  
    +OnSessionAccept()  
    +OnSessionDisconnect()  
  }

  class GateUnitManageComponent {
    -Dictionary Units  
    -Dictionary UnitsByUserName  
    +Add(userName, session): GateUnit  
    +Remove(id_or_name)  
    +ForEachUnitSession(): IEnumerable  
  }

  class GateUnit {
    +long Id  
    +string UserName  
    +Session Session  
    +Dictionary Routes  
    +Dispose()  
  }

  class GateUnitFlagComponent {
    +long GateUnitId  
  }

  class RouteComponent {
    -Dictionary addressMap  
    +AddAddress(sceneType, unitRuntimeId)  
    +Send(toSceneType, message)  
    +Call(toSceneType, request)  
  }

  GateScene --> GateUnitManageComponent : 挂载  
  GateScene --> Session : 创建  
  Session --> GateUnitFlagComponent : 挂载  
  Session --> RouteComponent : 绑定  
  GateUnitManageComponent --> GateUnit : 管理  
  GateUnit --> RouteComponent : 使用Routes

GateScene

  • 方法

    • Start():启动网络框架
    • OnSessionAccept():新客户端连接,创建 Session 并挂载 Flag & Route
    • OnSessionDisconnect():客户端断开,销毁 Flag 触发下线

GateUnitManageComponent

  • 字段

    • Units / UnitsByUserName:双索引缓存
  • 方法

    • Add(userName, session):创建或更新 GateUnit
    • Remove(id or name):移除并通知多后端
    • ForEachUnitSession():遍历所有有效 Session

GateUnit

  • 字段

    • Id, UserName, Session
    • Routes:后端路由字典(SceneType → UnitRuntimeId)
  • 方法

    • Dispose():释放自身,触发对应的下线通知

GateUnitFlagComponent

  • 字段

    • GateUnitId:与 Session 绑定的 GateUnit

RouteComponent

  • 字段

    • addressMap:SceneType → UnitRuntimeId
  • 方法

    • AddAddress(sceneType, unitRuntimeId):注册路由
    • Send(toSceneType, message):透明转发消息
    • Call(toSceneType, request):透明发起 RPC

Gate 服核心流程

sequenceDiagram
  autonumber
  participant ClientSession
  participant GateSession
  participant ChatSession
  participant MapSession

  ClientSession->>GateSession: 1. C2G_LoginRequest { UserName }
  GateSession->>GateSession: 2. 绑定 GateUnitFlagComponent & RouteComponent
  GateSession->>GateUnitManageComponent: 3. Add(userName, session)
  GateSession->>ChatSession: 4. G2Chat_LoginRequest { UserName, UnitId, GateRouteId }
  ChatSession-->>GateSession: 5. Chat2G_LoginResponse { ChatRouteId }
  GateSession->>MapSession: 6. G2M_LoginRequest { ChatUnitRouteId }
  MapSession-->>GateSession: 7. M2G_LoginResponse { MapRouteId }
  GateSession-->>ClientSession: 8. G2C_LoginResponse { ErrorCode=0, ChatRouteId, MapRouteId }

  ClientSession->>GateSession: 9. C2Chat_SendMessageRequest { ChatInfoTree }
  GateSession->>RouteComponent: 10. route → ChatSession
  GateSession->>ChatSession: 11. Other2Chat_ChatMessage { ChatInfoTree }
  ChatSession-->>GateSession: 12. Chat2G_ChatMessage or Chat2C_ChatMessage { ChatInfoTree, TargetList? }
  GateSession->>GateUnitManageComponent: 13. ForEachUnitSession() or Send to specific GateSessionRunTimeIDs
  GateSession-->>ClientSession: 14. Chat2C_Message { ChatInfoTree }

Gate 服核心流程说明

  1. 客户端发起登录
    ClientSession 发送 C2G_LoginRequestGateSession,携带用户名进行鉴权与会话建立。

  2. 会话初始化
    GateSession 上挂载 GateUnitFlagComponent(保存 GateUnitId)和 RouteComponent(维护后端路由映射)。

  3. 注册 GateUnit
    调用 GateUnitManageComponent.Add(),将或更新 GateUnit 实体(包含用户名、Session 引用、路由字典等)到内存缓存。

  4. 向 Chat 服上线
    GateSession 发起 G2Chat_LoginRequest,告知 Chat 服务器该用户上线,并获取 ChatRouteId(ChatUnit 的 RunTimeId)。

  5. Chat 服返回路由 ID
    ChatSession 回复 Chat2G_LoginResponse,包含 ChatRouteId,Gate 将其保存至路由字典。

  6. 向 Map 服上线
    随后 GateSession 发起 G2M_LoginRequest,将 ChatRouteId 转给 Map 服务器,让 Map 服记录此聊天路由。

  7. Map 服返回路由 ID
    Map 服务器通过 M2G_LoginResponse 返回 MapRouteId,Gate 服更新对应路由映射。

  8. Gate 返回登录响应
    Gate 汇总所有后端返回的路由信息,发送 G2C_LoginResponse 给客户端,登录流程完成。

  9. 客户端发起聊天请求
    登录成功后,客户端构造 ChatInfoTree 并调用 C2Chat_SendMessageRequest 至 Gate。

  10. Gate 路由到 Chat 服
    Gate 利用 RouteComponent 自动将聊天请求转发到指定的 ChatSession

  11. Chat 服分发消息
    ChatSession 根据频道类型(世界、公会、私聊等)通过 ChatSceneHelper.Distribution() 处理消息,并生成回传消息:

    • Chat2G_ChatMessage:用于广播到所有客户端(通过 GateUnitManageComponent 遍历所有 GateSession)
    • Chat2C_ChatMessage:用于私聊或定向广播,包含具体的目标 GateSession RunTimeID 列表
  12. Chat 服回传 Gate
    Chat 服将处理好的消息(Chat2G_ChatMessageChat2C_ChatMessage)发送回 Gate。

  13. Gate 分发至客户端

    • 对于 Chat2G_ChatMessage,Gate 遍历所有在线 GateSession 并发送;
    • 对于 Chat2C_ChatMessage,Gate 直接将消息发给列表中指定的 GateSession RunTimeIDs。
  14. 客户端接收并展示
    ClientSession 收到 Chat2C_Message,解析 ChatInfoTree 并渲染到 UI。

此流程保证了:

  • 单一入口:所有客户端通信均从 Gate 进入,后端无须单独公开端口。
  • 双向路由:请求和响应通过同一条路由表透明转发,客户端只需与 Gate 打交道。
  • 状态一致:上下线逻辑统一在 Gate 触发,Chat/Map 只聚焦业务分发与回收。

Gate服上下线流程说明

客户端发起登录

ClientSession 发送 C2G_LoginRequestGateSession,携带用户名进行鉴权与会话建立。此时进入 Gate 服务器处理流程:

  1. GateSession 首先进入 Gate,然后到达 Gate用户管理中心
  2. 检查用户实体是否在缓存中:
    • 若在缓存中,直接从缓存中拿到实体。
    • 若不在缓存中,创建实体并添加到缓存中。
  3. 之后执行登录到其他服务器(如 Chat 服务器、Map 服务器等)的操作 ,在 GateSession 上挂载 GateUnitFlagComponent(保存 GateUnitId)和 RouteComponent(维护后端路由映射);调用 GateUnitManageComponent.Add(),将或更新 GateUnit 实体(包含用户名、Session 引用、路由字典等)到内存缓存;GateSession 发起 G2Chat_LoginRequest,告知 Chat 服务器该用户上线,并获取 ChatRouteId(ChatUnit 的 RunTimeId)等。

客户端下线流程

当客户端发起下线操作时:

  1. ClientSession 进入 Gate,然后设置延迟卸载。
  2. 触发其他服务器执行下线操作。
  3. 最后在缓存中移除对应的用户实体。

总结

  • 职责分离

    • Gate 服:专注连接管理、会话生命周期和透明路由;对外仅暴露单一入口,简化客户端逻辑与监控。
    • Chat/Map 服:专注聊天业务与世界逻辑,摆脱网络细节耦合,便于热更新与弹性扩缩。
  • 组件化设计

    • FlagComponent:会话→用户映射,实现登录绑定与断线触发下线。
    • RouteComponent:维护后端路由表,实现客户端请求与响应的自动双向转发。
    • UnitManageComponent:内存中高效管理在线实体,结合超时策略支持延迟销毁与重连容错。
  • 流程流畅

    • 登录阶段在 Gate 端完成所有路由注册,后端各负其责;
    • 聊天消息全程经由 Gate 转发,Chat 服只需关心消息分发与频道管理;
    • 回程同理,保证上下行一致性、简单可靠。
  • 可扩展性与健壮性

    • 单 Chat 节点即可承载数万用户;
    • 动态添加 Chat/Map 实例时,只需更新路由映射,无需客户端改动;
    • 组件化、解藕化的设计使得功能迭代与运维更为便捷。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏