我为什么给 Unity 客户端配了一个自己的 C++ 服务器?
前几篇文章里,我介绍了自己开源的 Unity 框架 MyFramework,也聊了它和 ET、QFramework 这类框架的定位差异。
这几天有人问到一个问题:
既然这是一个 Unity 框架,为什么还要配一个 C++ 服务器框架?
这个问题很合理。
因为很多 Unity 客户端框架,只需要解决客户端内部的问题就够了。
比如:
-
UI 怎么管理
-
资源怎么加载
-
对象池怎么封装
-
事件系统怎么设计
-
热更新怎么接入
-
配置表怎么读取
这些都属于 Unity 客户端内部的工程问题。
但如果项目是 RPG、MMO、SLG、模拟经营或者其他长期联网项目,只考虑客户端是不够的。
因为真正麻烦的地方,往往不只是客户端怎么写,而是:
客户端和服务器之间如何长期保持一致。
所以我最终把服务器框架也整理出来了。
客户端框架:
配套服务器框架:
GitHub - ZHOURUIH/MyServerFramework · GitHub
一、为什么 Unity 框架不能只看客户端
很多 Unity 项目一开始都是先做客户端。
先做界面。
先做角色。
先做地图。
先做战斗表现。
先用本地数据模拟流程。
这样做 Demo 没问题,而且效率很高。
但项目一旦进入真实联网阶段,很多问题就会出现。
比如:
-
登录协议怎么定义
-
角色数据从哪里来
-
背包数据怎么同步
-
技能请求怎么发送
-
服务器怎么返回战斗结果
-
配置 ID 客户端和服务器是否一致
-
消息字段顺序是否一致
-
数据库结构和代码结构是否一致
-
客户端改了协议,服务器有没有同步
-
服务器新增字段,客户端是否漏处理
这些问题不属于单纯 Unity 客户端内部问题。
它们是客户端和服务器协作问题。
如果只做一个客户端框架,很容易做到后面发现:
客户端内部看起来很整齐,但一连服务器就开始混乱。
所以我不太希望 MyFramework 只是一个“单机 Unity 工程框架”。
我更希望它是一套围绕真实游戏开发流程整理出来的工程体系。
而真实联网项目里,服务器是绕不开的。
二、服务器不是为了炫技,而是为了闭环
我写配套服务器框架,不是为了证明自己一定要写服务器。
也不是为了说所有 Unity 项目都应该自己写 C++ 服务端。
很多项目完全可以使用现成后端、云服务、Node、Go、C#、Java,甚至只用 HTTP 接口。
这些都没问题。
我做 MyServerFramework 的核心原因是:
我需要让客户端框架和服务器框架形成闭环。
这个闭环主要体现在几个地方:
-
协议定义闭环
-
配置表闭环
-
数据库结构闭环
-
客户端请求闭环
-
服务器返回闭环
-
Demo 流程闭环
-
工具链生成闭环
如果只有客户端,没有服务器,那么很多东西只能停留在“客户端模拟”。
比如登录界面可以写,但登录到底怎么走协议?
角色数据可以写本地假数据,但服务器真实返回的数据结构是什么?
攻击按钮可以点,但服务器收到攻击请求以后怎么回包?
背包 UI 可以显示,但物品数据从服务器哪里来?
所以我需要一个服务器框架来配合客户端,把这些流程真正跑通。
这才是配套服务器的意义。
三、为什么选择 C++ 服务器
这个选择很大程度上和我的开发习惯有关。
我个人一直比较偏传统游戏服务器和游戏引擎式的开发思路。
相比一些更偏现代框架风格的方案,我更喜欢:
-
显式生命周期
-
明确模块边界
-
强控制
-
少隐藏流程
-
对象池
-
自定义内存管理
-
明确的初始化、更新、销毁流程
这些思路在 MyFramework 客户端里也能看到。
例如:
-
FrameSystem
-
CommandSystem
-
EventSystem
-
ClassPool
-
自定义 UI 封装
-
显式资源管理
-
热更新分层
-
代码生成工具链
服务器框架也是同样思路。
C++ 服务端对我来说更容易控制底层行为。
当然,这不代表 C++ 一定比其他语言更适合所有项目。
如果团队更熟 C#,用 C# 服务端完全没问题。
如果团队更熟 Go,Go 也可以。
如果只是轻量接口,Node 或 Java 也可以。
但对我自己的工程体系来说,C++ 服务器更符合我的长期维护习惯。
所以 MyServerFramework 不是为了告诉别人“服务器必须用 C++”。
而是提供一个:
Unity 客户端 + C++ 服务器配套开发流程的参考实现。
四、最重要的是协议一致性
客户端和服务器通信时,最怕的不是连接失败。
连接失败通常很明显。
最怕的是双方对同一条消息的理解不一致。
比如客户端认为一条消息是:
角色ID
道具ID
数量
服务器却认为是:
角色ID
数量
道具ID
字段顺序不一致,解析出来的数据就可能完全错乱。
再比如客户端把某个字段改成了 int,服务器还认为它是 long。
或者服务器新增了字段,客户端没有同步。
这类问题有时候不会马上崩溃,而是表现成非常奇怪的业务错误。
所以我认为协议不应该靠手写同步。
MyFramework 和 MyServerFramework 都围绕协议生成做了配套。
协议定义可以生成:
-
客户端消息类
-
服务器消息类
-
消息 ID
-
注册代码
-
序列化代码
-
反序列化代码
这样客户端和服务器就不是靠“人记住要改两边”。
而是通过工具生成来保持一致。
这也是我给客户端配服务器的一个核心原因。
因为只有两端都存在,协议工具链才有实际意义。
五、配置表也需要客户端和服务器一致
除了协议以外,配置表也是非常容易出问题的地方。
很多游戏里,客户端和服务器都会用到配置表。
比如:
-
道具表
-
技能表
-
怪物表
-
任务表
-
地图表
-
掉落表
-
商店表
-
活动表
客户端可能需要用配置表显示名称、图标、描述、特效。
服务器可能需要用配置表判断消耗、奖励、数值、限制条件。
如果客户端和服务器读的是不同结构,或者代码生成不一致,就容易出问题。
比如:
客户端显示技能消耗 10 点蓝。
服务器判断技能消耗 20 点蓝。
客户端认为道具类型是装备。
服务器认为道具类型是材料。
这种问题最终都会变成联调成本。
所以配置表工具链也应该尽量形成两端闭环。
MyFramework 关注客户端配置读取。
MyServerFramework 关注服务器配置读取。
两边都可以围绕同一套配置结构生成代码。
这不是为了让配置表看起来更高级,而是为了减少长期项目里的同步错误。
六、Demo 不应该只是本地假流程
很多框架 Demo 做得很漂亮。
按钮能点。
界面能跳。
角色能动。
数据能显示。
但如果所有数据都是本地模拟的,那么它只能说明客户端表现流程跑通了。
它不能说明客户端和服务器真的能协作。
我更希望 MyFramework 的 Demo 至少能具备一些基础联调能力。
比如:
-
连接服务器
-
检查协议版本
-
Ping 往返
-
登录
-
获取角色数据
-
攻击请求
-
服务器返回结果
-
客户端刷新表现
这些流程看起来不复杂,但它们非常关键。
因为它们证明框架不只是“单机 UI 和资源管理”,而是能够接入真实网络流程。
一旦登录、Ping、攻击、角色数据这些基础流程跑通,后续继续扩展背包、任务、邮件、聊天、商城、活动,就有了基础结构。
所以服务器 Demo 的意义不是功能多,而是把客户端和服务器的通信路径跑通。
七、服务器框架里包含哪些基础模块
MyServerFramework 不是一个只回包的 Echo Server。
它里面也整理了一些常见服务器基础模块。
例如:
-
TCP Server
-
UDP Server
-
WebSocket Server
-
HTTP Server
-
TCP Client
-
HTTP Client
-
协议生成
-
MySQL 访问
-
SQLite 配置读取
-
配置表管理
-
命令系统
-
事件系统
-
对象池
-
角色管理
-
组件系统
-
状态机
-
定时任务
-
日志系统
-
单元测试
-
Windows / Linux 编译支持
这些模块并不是为了堆功能。
而是因为一个长期服务器项目,最终都会遇到这些基础问题。
例如:
网络层需要收发消息。
数据库层需要存账号、角色和业务数据。
配置表需要被服务器读取。
命令系统可以降低模块耦合。
事件系统可以做状态通知。
对象池可以减少频繁创建销毁。
定时任务可以做服务器周期逻辑。
日志系统可以帮助线上定位问题。
这些东西单独看都不神奇。
但组合起来,才像一个可以继续扩展的服务器框架。
八、客户端和服务器的关系不是“谁依赖谁”
我不希望 MyFramework 和 MyServerFramework 被理解成:
客户端必须依赖这个服务器。
或者:
服务器必须依赖这个客户端。
它们当然可以配套使用,但不是强制绑定。
更准确地说:
MyFramework 提供 Unity 客户端工程化方案。
MyServerFramework 提供 C++ 服务器工程化方案。
两者之间通过协议、配置、网络消息和工具链建立联系。
你可以只研究客户端。
也可以只研究服务器。
也可以把两者一起看,理解一套完整的客户端/服务器开发流程。
我认为这种关系比较合理。
因为不同开发者的需求不一样。
有的人只关心 Unity 客户端架构。
有的人只关心 C++ 服务器。
有的人想研究完整流程。
开源后,我希望这些人都能找到自己需要的部分。
九、这和 ET 的区别是什么
前一篇文章里已经聊过 ET 和 MyFramework 的区别。
这里再简单说一下服务器方向。
ET 的服务端是整个框架非常核心的能力。
它更偏:
-
双端 C#
-
分布式服务器
-
Actor / Fiber
-
多进程
-
热重载
-
大型在线游戏架构
这是 ET 很强的方向。
MyFramework + MyServerFramework 不是去复刻这个方向。
我的服务器框架更偏:
-
C++ 服务端
-
和 Unity 客户端配套
-
协议生成闭环
-
配置表生成闭环
-
数据库和基础服务器模块
-
显式生命周期和强控制风格
所以它们并不是同一种选择。
如果你要研究 C# 双端分布式服务器,ET 很值得看。
如果你更关心 Unity 客户端和 C++ 服务器如何通过工具链配套,那么 MyFramework + MyServerFramework 会更贴近这个方向。
十、为什么我认为服务器配套能提升框架可信度
一个 Unity 框架如果只有客户端,当然也可以有价值。
但对于联网游戏来说,有服务器配套会让很多设计更容易被验证。
比如协议生成是否真的有用?
配置表双端生成是否真的有意义?
网络消息封装是否能跑通?
登录流程是否能联调?
客户端和服务器的数据结构是否一致?
这些问题只有在两端一起跑的时候,才更容易暴露。
如果只在客户端内部模拟,很多问题会被隐藏起来。
所以我觉得配套服务器能提升框架可信度。
它至少说明:
这些设计不是只在客户端里自洽,而是有机会在客户端和服务器之间跑通。
这对一个长期游戏项目来说很重要。
十一、MyServerFramework 目前适合什么人
MyServerFramework 不是一个“下载后马上就能做完整 MMO”的项目。
它更适合下面几类人:
1. 想研究 Unity 客户端和 C++ 服务器配套流程的人
如果你想知道客户端协议、服务器协议、配置、数据库、登录、Ping、攻击这些流程怎么串起来,它可以作为参考。
2. 想学习传统 C++ 游戏服务器框架组织方式的人
如果你对 C++ 服务器里的模块划分、对象池、命令系统、事件系统、组件、状态机、日志、数据库封装感兴趣,也可以看它的结构。
3. 已经有服务器经验,想参考另一种实现方式的人
如果你已经写过服务端,不一定需要直接使用它,但可以参考其中的工具链和组织方式。
4. 正在研究 MyFramework 的人
如果你正在看 MyFramework 客户端,那么配套服务器可以帮助你理解协议、配置和联调流程为什么要这样设计。
十二、MyServerFramework 不适合什么人
同样,它也不是适合所有人。
1. 不适合只想要即插即用后端的人
如果你只是想找一个现成后端,最好能直接上线业务,那它不是这个方向。
它更像一个框架和工程参考,而不是一键部署的商业后端服务。
2. 不适合完全不想碰 C++ 的人
如果你的团队完全不使用 C++,也不想维护 C++ 服务端,那它可能不适合直接采用。
可以只参考思路,不一定要用代码。
3. 不适合想找完整分布式 MMO 方案的人
如果你目标是完整分布式服务器、跨服架构、动态扩缩容、Actor 模型等,ET 这类框架更适合深入研究。
MyServerFramework 当前更偏基础服务器框架和客户端配套流程。
十三、我希望最终形成什么样的开源项目
我希望 MyFramework 和 MyServerFramework 最终不是两个孤立仓库。
而是形成一个比较完整的游戏开发参考体系:
Unity 客户端框架
↓
UI 自动生成
↓
配置表工具链
↓
协议生成
↓
C++ 服务器框架
↓
数据库
↓
客户端和服务器联调
这个体系不一定适合所有人直接使用。
但它可以给开发者一个参考:
一个长期 Unity 项目,从客户端到服务器,工程化工具链可以怎么组织。
对我来说,这比单独开源一个 UI 框架或者资源管理器更有意义。
因为长期项目的问题往往不是某一个模块的问题,而是整个流程的问题。
结语
我给 Unity 客户端配一个 C++ 服务器,不是为了让这个项目看起来更复杂。
恰恰相反,是因为真实联网游戏项目本来就复杂。
如果只看客户端,很多问题会被隐藏。
如果客户端和服务器一起看,协议、配置、数据、网络、数据库、工具链这些问题都会暴露出来。
MyFramework 解决的是 Unity 客户端工程化问题。
MyServerFramework 解决的是配套 C++ 服务器和联调流程问题。
它们放在一起,才更接近我想表达的方向:
不是一个单纯的 Unity Demo 框架。
而是一套围绕长期游戏项目整理出来的客户端/服务器工程化参考。
项目地址:
配套服务器框架:
更多推荐
所有评论(0)