心跳插件

    getty提供了心跳插件HeartBeatTimeOutHandler,可以监测并移除长时间没有心跳或数据读写的客户端连接,及时释放资源

    1. AioServerStarter server = new AioServerStarter(8888);
    2. server.channelInitializer(new ChannelInitializer() {
    3. @Override
    4. public void initChannel(AioChannel channel) throws Exception {
    5. DefaultChannelPipeline defaultChannelPipeline = channel.getDefaultChannelPipeline();
    6. //添加心跳起搏器,设置心跳时间间隔
    7. defaultChannelPipeline.addLast(new IdleStateHandler(channel, 2, 0));
    8. //注册心跳插件则可以生效,心跳插件最好添加到消息处理器的前端
    9. defaultChannelPipeline.addLast(new HeartBeatTimeOutHandler());
    10. defaultChannelPipeline.addLast(new DelimiterFrameDecoder(DelimiterFrameDecoder.lineDelimiter));
    11. defaultChannelPipeline.addLast(new StringDecoder());
    12. defaultChannelPipeline.addLast(new SimpleHandler());
    13. }
    14. });
    15. 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次再移除,在各种应用场景设计中是比较合理的。

    1. @Override
    2. public void userEventTriggered(AioChannel aioChannel, IdleState evt) {
    3. if (evt == IdleState.READER_IDLE) {
    4. loss_connect_time++;
    5. if (loss_connect_time > 2) {
    6. // 超过3次检测没有心跳就关闭这个连接
    7. try {
    8. logger.info("[closed inactive channel:" + aioChannel.getRemoteAddress().getHostString() + "]");
    9. } catch (IOException e) {
    10. e.printStackTrace();
    11. }
    12. aioChannel.close();
    13. }
    14. } else {
    15. super.userEventTriggered(aioChannel, evt);
    16. }
    17. }