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 { -DictionaryUnits -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 & RouteOnSessionDisconnect()
:客户端断开,销毁 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 服核心流程说明
客户端发起登录
ClientSession
发送C2G_LoginRequest
至GateSession
,携带用户名进行鉴权与会话建立。会话初始化
在GateSession
上挂载GateUnitFlagComponent
(保存 GateUnitId)和RouteComponent
(维护后端路由映射)。注册 GateUnit
调用GateUnitManageComponent.Add()
,将或更新GateUnit
实体(包含用户名、Session 引用、路由字典等)到内存缓存。向 Chat 服上线
GateSession
发起G2Chat_LoginRequest
,告知 Chat 服务器该用户上线,并获取ChatRouteId
(ChatUnit 的 RunTimeId)。Chat 服返回路由 ID
ChatSession
回复Chat2G_LoginResponse
,包含ChatRouteId
,Gate 将其保存至路由字典。向 Map 服上线
随后GateSession
发起G2M_LoginRequest
,将ChatRouteId
转给 Map 服务器,让 Map 服记录此聊天路由。Map 服返回路由 ID
Map 服务器通过M2G_LoginResponse
返回MapRouteId
,Gate 服更新对应路由映射。Gate 返回登录响应
Gate 汇总所有后端返回的路由信息,发送G2C_LoginResponse
给客户端,登录流程完成。客户端发起聊天请求
登录成功后,客户端构造ChatInfoTree
并调用C2Chat_SendMessageRequest
至 Gate。Gate 路由到 Chat 服
Gate 利用RouteComponent
自动将聊天请求转发到指定的ChatSession
。Chat 服分发消息
ChatSession
根据频道类型(世界、公会、私聊等)通过ChatSceneHelper.Distribution()
处理消息,并生成回传消息:- Chat2G_ChatMessage:用于广播到所有客户端(通过 GateUnitManageComponent 遍历所有 GateSession)
- Chat2C_ChatMessage:用于私聊或定向广播,包含具体的目标 GateSession RunTimeID 列表
Chat 服回传 Gate
Chat 服将处理好的消息(Chat2G_ChatMessage
或Chat2C_ChatMessage
)发送回 Gate。Gate 分发至客户端
- 对于
Chat2G_ChatMessage
,Gate 遍历所有在线 GateSession 并发送; - 对于
Chat2C_ChatMessage
,Gate 直接将消息发给列表中指定的 GateSession RunTimeIDs。
- 对于
客户端接收并展示
ClientSession
收到Chat2C_Message
,解析ChatInfoTree
并渲染到 UI。
此流程保证了:
- 单一入口:所有客户端通信均从 Gate 进入,后端无须单独公开端口。
- 双向路由:请求和响应通过同一条路由表透明转发,客户端只需与 Gate 打交道。
- 状态一致:上下线逻辑统一在 Gate 触发,Chat/Map 只聚焦业务分发与回收。
Gate服上下线流程说明
客户端发起登录
ClientSession
发送 C2G_LoginRequest
至 GateSession
,携带用户名进行鉴权与会话建立。此时进入 Gate 服务器处理流程:
GateSession
首先进入Gate
,然后到达Gate用户管理中心
。- 检查用户实体是否在缓存中:
- 若在缓存中,直接从缓存中拿到实体。
- 若不在缓存中,创建实体并添加到缓存中。
- 之后执行登录到其他服务器(如 Chat 服务器、Map 服务器等)的操作 ,在
GateSession
上挂载GateUnitFlagComponent
(保存 GateUnitId)和RouteComponent
(维护后端路由映射);调用GateUnitManageComponent.Add()
,将或更新GateUnit
实体(包含用户名、Session 引用、路由字典等)到内存缓存;GateSession
发起G2Chat_LoginRequest
,告知 Chat 服务器该用户上线,并获取ChatRouteId
(ChatUnit 的 RunTimeId)等。
客户端下线流程
当客户端发起下线操作时:
ClientSession
进入Gate
,然后设置延迟卸载。- 触发其他服务器执行下线操作。
- 最后在缓存中移除对应的用户实体。
总结
职责分离
- Gate 服:专注连接管理、会话生命周期和透明路由;对外仅暴露单一入口,简化客户端逻辑与监控。
- Chat/Map 服:专注聊天业务与世界逻辑,摆脱网络细节耦合,便于热更新与弹性扩缩。
组件化设计
- FlagComponent:会话→用户映射,实现登录绑定与断线触发下线。
- RouteComponent:维护后端路由表,实现客户端请求与响应的自动双向转发。
- UnitManageComponent:内存中高效管理在线实体,结合超时策略支持延迟销毁与重连容错。
流程流畅
- 登录阶段在 Gate 端完成所有路由注册,后端各负其责;
- 聊天消息全程经由 Gate 转发,Chat 服只需关心消息分发与频道管理;
- 回程同理,保证上下行一致性、简单可靠。
可扩展性与健壮性
- 单 Chat 节点即可承载数万用户;
- 动态添加 Chat/Map 实例时,只需更新路由映射,无需客户端改动;
- 组件化、解藕化的设计使得功能迭代与运维更为便捷。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com