游戏对外服设计
如果你不关心游戏对外服整体脉络与设计的,只想知道如何使用、如何做功能扩展等内容, 请阅读游戏对外服介绍。
从架构简图中,我们知道了整体架构由三部分组成,分别是 1.游戏对外服、2.游戏网关、3.游戏逻辑服,三者既可相互独立,又可相互融合。
游戏对外服在架构图位置的左边部分,ExternalServer。
介绍
在阅读本文时,需要你具备一定的 Netty 知识。 通过本篇的学习,你可以知道游戏对外服的整体设计。
了解整体设计后,你可以
- 扩展更多的连接方式。
- 添加一些自定义的 Netty Handler。
- 集成第三方通信框架,框架默认实现是 Netty。
UML
我们先看游戏对外服的 UML 图。
游戏对外服由两部分构成
- ExternalCore,负责外部通信,创建与真实玩家连接的服务器。
- ExternalBrokerClientStartup,负责内部通信,与 Broker(游戏网关)建立连接。
ExternalCore 负责外部通信的接口,默认实现类 DefaultExternalCore 是基于 Netty 的实现。 开发者如有需要可以实现其他的通信框架,如 Mina、smart-socket。
MicroBootstrap 是与真实玩家连接的服务器,帮助开发者屏蔽连接方式的细节, 如 TCP、WebSocket、UDP、KCP、QUIC 等。 目前框架默认提供了 TCP、WebSocket、UDP 连接协议,如有需要,开发者可以在这里扩展自己的连接协议,以提供更多的连接方式。
核心接口介绍
游戏对外服总体来说只有四个核心接口,如果你只打算做功能扩展,通常只需要关注 MicroBootstrapFlow 接口。
由 ExternalCore 和 ExternalBrokerClientStartup 组成的一个整体。
职责 : 启动 ExternalCore 和 ExternalBrokerClientStartup 。
帮助开发者屏蔽各通信框架的细节,你可以使用如 Netty、Mina、smart-socket 等通信框来实现该接口, 框架默认提供了基于 Netty 的实现。
职责 : 负责外部通信,创建与真实玩家连接的服务器。
帮助开发者屏蔽连接方式的细节,如 TCP、WebSocket、UDP、KCP、QUIC 等。
职责 : 与真实玩家连接的服务器。
与真实玩家连接的启动流程,开发者可通过此接口做业务编排与功能扩展,也就是自定义一些 Netty Handler。 开发者可以选择性的重写流程方法,来定制符合自身项目的业务。
职责 : 业务编排、功能扩展,也是开发者在扩展时接触最多的一个接口。
ExternalCore
通过 UML 图,可以了解到 ExternalCore 接口可以采用不同的通信框架实现。
ExternalCore 的设计可以帮助开发者屏蔽各通信框架的细节,你可以使用如 Netty、Mina、smart-socket 等通信框来实现该接口, 框架默认提供了基于 Netty 的实现 DefaultExternalCore。
开发者如有需要,可以考虑基于 Mina、smart-socket 等通信框架来提供一个游戏对外服的实现。 即使采用 Mina、smart-socket 这些通信框架提供的游戏对外服实现,也不会影响现有的游戏逻辑服业务逻辑。 这是因为游戏对外服实现了单一职责原则,只负责用户连接相关的维护。
该设计可以使得游戏对外服的扩展变得更加简单和灵活。
MicroBootstrap
MicroBootstrap 是与真实玩家连接的服务器,如果说 ExternalCore 接口是用来屏蔽不同的通信框架, 那么 MicroBootstrap 接口则是帮助开发者屏蔽不同的连接方式。
开发者可以扩展不同的连接方式,如 TCP、WebSocket、UDP、KCP、QUIC 等。
连接方式
连接方式 | 框架是否提供 |
---|---|
TCP | ✅ |
WebSocket | ✅ |
UDP | ✅ 只对部分成员开放 |
KCP | ❌ (在计划中) |
QUIC | ❌ (在计划中) |
目前,框架已经提供了 TCP、WebSocket 和 UDP 连接方式,并且也支持在这几种连接方式之间进行灵活切换。
连接方式的切换对业务代码没有任何影响,无需做出任何改动即可实现连接方式的更改。
扩展连接方式
MicroBootstrap 在扩展上也是简单的,游戏对外服在扩展无连接的 UDP 时, 只用了 400+ 行 java 代码就完成了与 TCP、WebSocket 相兼容的扩展(包括路由权限、心跳、UserSession 管理...等)。 这意味着,将来我们实现 KCP、QUIC 的扩展时,也是简单的。
在扩展时,可以参考已有的实现类源码 SocketMicroBootstrap、 UdpMicroBootstrap
连接特性 | 类名 | 已提供的连接方式 | 计划中的连接方式 |
---|---|---|---|
长连接 | SocketMicroBootstrap | TCP、WebSocket | QUIC |
无连接 | UdpMicroBootstrap | UDP | KCP |
MicroBootstrapFlow
职责 : 业务编排、功能扩展,也是开发者在扩展时接触最多的一个接口。
与真实玩家连接的启动流程,开发者可通过此接口做业务编排与功能扩展,也就是自定义一些 Netty Handler。 开发者可以选择性的重写流程方法,来定制符合自身项目的业务。 开发者可通过此接口对服务器做编排,编排分为构建时、新建连接时两种。
- createFlow: 构建时,此时服务器还没启动。该方法是构建时的执行流程,方法内调用了 option、channelInitializer 方法。
- option,可以给服务器做一些 option 设置。
- channelInitializer,可以给服务器做一些业务编排。
- pipelineFlow: 新建连接时,服务器已经启动,每次有新连接进来时,会触发。
该方法是新建连接时的执行流程,方法内调用了 pipelineCodec、pipelineIdle、pipelineCustom 方法。
- pipelineCodec,编解码相关的编排。
- pipelineIdle,心跳相关的编排。
- pipelineCustom,自定义的业务编排。
channelInitializer
方法在初始化 ChannelInitializer 时,在方法内调用了 pipelineFlow 方法, 而 pipelineFlow 内默认编排了 pipelineCodec、pipelineIdle、pipelineCustom 方法的执行流程。 开发者可以任选一个方法来重写,但大部分情况下只需要重写 pipelineCustom 就可以达到很强的扩展了。
- pipelineCodec,编解码相关的编排。
- pipelineIdle,心跳相关的编排。
- pipelineCustom,自定义的业务编排,大部分情况下只需要重写 pipelineCustom 就可以达到很强的扩展了。
abstract class SocketMicroBootstrapFlow extends AbstractMicroBootstrapFlow<ServerBootstrap> {
@Override
public void channelInitializer(ServerBootstrap bootstrap) {
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
DefaultPipelineContext pipelineContext = new DefaultPipelineContext(ch, setting);
pipelineFlow(pipelineContext);
}
});
}
}
public interface MicroBootstrapFlow<Bootstrap> {
...
void channelInitializer(Bootstrap bootstrap);
default void pipelineFlow(PipelineContext pipelineContext) {
pipelineCodec(pipelineContext);
pipelineIdle(pipelineContext);
pipelineCustom(pipelineContext);
}
}
pipelineCustom
pipelineCustom 是自定义的业务编排方法,大部分情况下只需要重写此方法就可以达到很强的扩展了。 开发者可以通过重写此方法,编排自己的 Handler,以满足你项目的业务需求。
默认情况下,框架为 pipelineCustom 方法添加了一些内置的 Netty Handler。
abstract class SocketMicroBootstrapFlow extends AbstractMicroBootstrapFlow<ServerBootstrap> {
...
@Override
public void pipelineCustom(PipelineContext context) {
...
context.addLast("CmdCheckHandler", CmdCheckHandler.me());
...
}
}
何时重写相关方法
- 如果框架默认提供的编解码部分不能满足你的业务,可以选择重写 pipelineCodec 方法。
- 如果框架默认提供的心跳部分不能满足你的业务,可以选择重写 pipelineIdle 方法。
- 如果框架默认提供的内置 Handler 部分 不能满足你的业务,或者说想做功能增强的,可以选择重写 pipelineCustom 方法。
- 如果 pipelineCodec、pipelineIdle、pipelineCustom 方法都不能满足你的业务,可以直接重写 pipelineFlow 方法。
- 其他的方法亦是如此。
小结
我们介绍了 ExternalServer、ExternalCore、MicroBootstrap、MicroBootstrapFlow 这几个核心接口及其职责。
游戏对外服的连接方式是可扩展的,这可以让游戏对外服支持更多的连接协议。
MicroBootstrapFlow 接口是与真实玩家连接的启动流程,开发者可通过此接口做业务编排与功能扩展,也就是自定义一些 Netty Handler。 开发者可以选择性的重写流程方法,来定制符合自身项目的业务。 开发者可通过此接口对服务器做编排,编排分为构建时、新建连接时两种。
- 【构建时】的执行流程 createFlow,createFlow 内调用了 option、channelInitializer 方法
- 【新建连接时】的执行流程 pipelineFlow,pipelineFlow 内调用了 pipelineCodec、pipelineIdle、pipelineCustom
MicroBootstrapFlow 接口的目的是尽可能地细化服务器创建和连接时的每个环节,以方便开发者对游戏对外服进行定制化扩展。 通常情况下,开发者只需要关注重写 MicroBootstrapFlow.pipelineCustom 方法,就可以实现很强的扩展了。
默认的游戏对外服基于 Netty 实现,因此如果开发者已经熟悉了 Netty 相关知识,扩展也就变得非常容易了。 如果之前没有接触过 Netty,可以先了解一下 Netty Handler 相关的内容,或查看框架内置的 Netty Handler 源码。
不必急于了解 Netty 的全部内容,只需关注 Netty Handler 部分,就可以进行功能扩展。 因为首要任务是将产品推向市场,如果需要进一步的扩展,基本上也只需要了解 Netty 的知识,并进行深入学习即可。
总之,框架默认提供的游戏对外服是基于 Netty 实现的,所以只需熟悉 Netty 相关知识,就可以轻松地应用到游戏对外服中了。