心跳插件
getty提供了心跳插件HeartBeatTimeOutHandler,可以监测并移除长时间没有心跳或数据读写的客户端连接,及时释放资源
AioServerStarter server = new AioServerStarter(8888);
server.channelInitializer(new ChannelInitializer() {
@Override
public void initChannel(AioChannel channel) throws Exception {
DefaultChannelPipeline defaultChannelPipeline = channel.getDefaultChannelPipeline();
//添加心跳起搏器,设置心跳时间间隔
defaultChannelPipeline.addLast(new IdleStateHandler(channel, 2, 0));
//注册心跳插件则可以生效,心跳插件最好添加到消息处理器的前端
defaultChannelPipeline.addLast(new HeartBeatTimeOutHandler());
defaultChannelPipeline.addLast(new DelimiterFrameDecoder(DelimiterFrameDecoder.lineDelimiter));
defaultChannelPipeline.addLast(new StringDecoder());
defaultChannelPipeline.addLast(new SimpleHandler());
}
});
server.start();
IdleStateHandler
IdleStateHandler是心跳发起的开始,我把它称为起搏器。它有三个参数
参数 | 类型 | 备注 |
---|---|---|
aioChannel | AioChannel | 当前通道 |
readerIdleTimeSeconds | int | 读消息间隔,配置为0则不生效 |
writerIdleTimeSeconds | int | 写消息间隔,配置为0则不生效 |
顾名思义,读消息间隔 就是当间隔多久没有消息读取则移除这个连接。写消息间隔 则是间隔多久没有写的动作则移除这个连接。
一般而言,只需配置读消息间隔即可,写消息间隔建议配置为0,getty只提供读动作的监听插件。
写动作其实实际应用中比较少用到,除非你确实需要这么干,那么你需要自己实现这个插件
心跳插件的原理
当配置了心跳插件以后,getty会根据配置的世界间隔,开启一个定时扫描的线程,每隔间隔时间扫描一次客户端连接,
如果间隔时间内,没有消息读取的连接,则loss_connect_time会累加一次,当loss_connect_time累加到3的时候,
也就是3次间隔时间内都没有消息读取,则框架会认为这个连接是不活跃的,则会移除这个连接。如果有消息读取,
那么loss_connect_time会重置为0,重新累计。
为什么会设置为3次,因为考虑到网络等各方面的原因,有时间隔时间内也许并没有收到读取消息,但下一次又收到了,
如果这个只累计一次就把连接移除,是不太合理的,累计3次再移除,在各种应用场景设计中是比较合理的。
@Override
public void userEventTriggered(AioChannel aioChannel, IdleState evt) {
if (evt == IdleState.READER_IDLE) {
loss_connect_time++;
if (loss_connect_time > 2) {
// 超过3次检测没有心跳就关闭这个连接
try {
logger.info("[closed inactive channel:" + aioChannel.getRemoteAddress().getHostString() + "]");
} catch (IOException e) {
e.printStackTrace();
}
aioChannel.close();
}
} else {
super.userEventTriggered(aioChannel, evt);
}
}