心跳设置与钩子
介绍
心跳的作用是在长连接中保持通信的活跃状态。
当客户端和服务端建立了长连接后,如果客户端长时间没有向服务器发送消息,服务端通常会断开该长连接。 客户端可以通过定期向服务器发送心跳包来保持连接的活跃状态,以防止被服务器断开。
心跳包是一种空的数据包,通过定期发送心跳包来模拟一次正常的数据传输,从而保证连接的连通性。 游戏对外服的职责之一是保持与用户的长连接,所以心跳相关的会在游戏对外服做设置。
开启心跳机制
只有游戏对外服需要开启心跳,我们可以在建构游戏对外服时, 将心跳相关的设置添加到 setting 中就可以了,下面这个示例在 idle 方法中演示了心跳整体时间的设置。
- code 2,创建 IdleProcessSetting,用于心跳相关的设置。
- code 3,心跳整体时间设置,包括 readerIdleTime、writerIdleTime、allIdleTime。
- code 5,添加心跳相关设置。
void idle(DefaultExternalCoreSetting setting) {
IdleProcessSetting idleProcessSetting = new IdleProcessSetting()
.setIdleTime(10);
setting.setIdleProcessSetting(idleProcessSetting);
}
ExternalServer createExternalServer(int externalCorePort) {
DefaultExternalServerBuilder builder = ...
DefaultExternalCoreSetting setting = builder.setting();
idle(setting);
...
return builder.build();
}
warning
如果开启了心跳机制,需要客户端在一定的时间间隔向服务器发送心跳消息,否则会被断开。
心跳钩子
IdleHook 心跳钩子接口提供了如下方法
- callback 方法,触发了 netty 心跳事件机制的回调方法。
- pongBefore 方法,将心跳消息响应给客户端前的回调钩子方法。
框架为 IdleHook 接口提供了一个默认实现类 DefaultSocketIdleHook,使用如下
...
void idle(DefaultExternalCoreSetting setting) {
IdleProcessSetting idleProcessSetting = new IdleProcessSetting()
.setIdleHook(new DefaultSocketIdleHook());
setting.setIdleProcessSetting(idleProcessSetting);
}
自定义心跳钩子
DemoIdleHook 是我们自定义心跳钩子。
- code 7,把当前时间戳给到心跳接收端,让客户端时间与服务器同步。
- code 12 ~ 14,创建错误消息,并通知客户端触发了心跳事件。
- code 16,返回 true 时,表示通知框架将当前用户的连接关闭。
- code 21,每秒更新当前时间。
@Slf4j
public class DemoIdleHook implements SocketIdleHook {
volatile byte[] timeBytes;
@Override
public void pongBefore(BarMessage idleMessage) {
idleMessage.setData(timeBytes);
}
@Override
public boolean callback(UserSession userSession, IdleStateEvent event) {
BarMessage message = ExternalCodecKit.createErrorIdleMessage(ActionErrorEnum.idleErrorCode);
message.setValidatorMsg(ActionErrorEnum.idleErrorCode.getMsg() + " : " + state.name());
userSession.writeAndFlush(message);
return true;
}
public DemoIdleHook() {
updateTime();
TaskKit.runInterval(this::updateTime, 1, TimeUnit.SECONDS);
}
private void updateTime() {
LongValue data = LongValue.of(CacheTimeKit.currentTimeMillis());
timeBytes = DataCodecKit.encode(data);
}
}
Example Source Code
see https://github.com/iohao/ioGameExamples
path : SimpleExample/example/example-hook