Netty 快速入门系列 - Chapter 4 Netty心跳【第十讲】 - IdleStateHandler学习

本文详细介绍了Netty中实现心跳机制的方法,包括Netty 3.x和5.x版本的心跳配置及代码示例,帮助读者理解如何通过IdleStateHandler检测会话状态并处理超时情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


IdleStateHandler 心跳作用:

心跳其实就是一个普通的请求,特点数据简单,业务也简单

心跳对于服务端来说,定时清除闲置会话inactive(netty5)、 channelclose(netty3)

心跳对客户端来说,用来检测会话是否断开,是否重连! 用来检测网络延时!

代码案例

Netty3.X

 channelPipeline.addLast("Idle", new IdleStateHandler(new HashedWheelTimer(), 5, 5, 10));

第一个5: 5s内是否有读操作

第二个5:5s内是否有回写操作

第三个: 10s内是否有读写操作

如果玩家超时,使用channelFuture.addListener 通知玩家后,关闭连接。

 if (e.getState() == IdleState.ALL_IDLE) {
       
       System.out.println("踢玩家下线!");


       ChannelFuture channelFuture = ctx.getChannel().write("timeout, you will close!");
       
       channelFuture.addListener(new ChannelFutureListener() {
          
          @Override
          public void operationComplete(ChannelFuture future) throws Exception {
            
            future.getChannel().close();
            
          }
       });

package com.john.netty.learn.ch06.netty3.x;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelSink;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timer;


public class HeartBeatServer {


  public HeartBeatServer(int port) {


     ServerBootstrap serverBootstrap = new ServerBootstrap();


     serverBootstrap.setFactory(new NioServerSocketChannelFactory(boss, workers));


     serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() {


       @Override
       public ChannelPipeline getPipeline() throws Exception {


          ChannelPipeline channelPipeline = Channels.pipeline();


          channelPipeline.addLast("Idle", new IdleStateHandler(new HashedWheelTimer(), 5, 5, 10));
          channelPipeline.addLast("Decoder", new StringDecoder());
          channelPipeline.addLast("HelloWorldHandler", new HeartBeatChannelHandler());
          channelPipeline.addLast("Encoder", new StringEncoder());


          return channelPipeline;
       }
     });


     serverBootstrap.bind(new InetSocketAddress(port));
  }


  private ExecutorService boss = Executors.newCachedThreadPool();


  private ExecutorService workers = Executors.newCachedThreadPool();


  public static void main(String[] args) {


     new HeartBeatServer(23);
  }
}
package com.john.netty.learn.ch06.netty3.x;


import java.text.SimpleDateFormat;
import java.util.Date;


import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.timeout.IdleState;
import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
import org.jboss.netty.handler.timeout.IdleStateEvent;


public class HeartBeatChannelHandler extends IdleStateAwareChannelHandler implements ChannelHandler {


  public HeartBeatChannelHandler() {


  }


  @Override
  public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {


     System.out.println("channelIdle " + e.getState() + " time:" + new SimpleDateFormat("ss").format(new Date()));


     if (e.getState() == IdleState.ALL_IDLE) {
       
       System.out.println("踢玩家下线!");


       ChannelFuture channelFuture = ctx.getChannel().write("timeout, you will close!");
       
       channelFuture.addListener(new ChannelFutureListener() {
          
          @Override
          public void operationComplete(ChannelFuture future) throws Exception {
            
            future.getChannel().close();
            
          }
       });
     }


  }


  /**
   * 接收到消息
   */
  @Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {


     // 没有过滤器
     // ChannelBuffer channelBuffer = (ChannelBuffer) e.getMessage();
     // System.out.println("接收到消息:" + new String(channelBuffer.array()));


     // 回写数据
     // ctx.getChannel().write(ChannelBuffers.wrappedBuffer(("Hi " +
     // e.getMessage()).getBytes()));


     // channelPipeline.addLast("Decoder", new StringDecoder());
     System.out.println("接收到消息:" + e.getMessage());


     // channelPipeline.addLast("Encoder", new StringEncoder());
     ctx.getChannel().write("Hi " + e.getMessage());


  }


  @Override
  public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
     System.out.println("channelConnected");
     super.channelConnected(ctx, e);
  }


  /**
   * 建立Channel成功,关闭通道时候,才会触发Disconnect
   */
  @Override
  public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {


     System.out.println("channelDisconnected");


     super.channelDisconnected(ctx, e);
  }


  /**
   * Channel 关闭
   */
  @Override
  public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {


     System.out.println("channelClosed");


     super.channelClosed(ctx, e);
  }


  /**
   * 捕获异常
   */


  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
     e.getCause().printStackTrace();
     super.exceptionCaught(ctx, e);
  }
}

--------------------------------------------------------------------------------------------------------------------------------

Netty5

Server : 

ch.pipeline().addLast(new IdleStateHandler(5, 5, 10));

Handler :  

 if (e.state() == IdleState.ALL_IDLE) {


      System.out.println("踢玩家下线!");

      ChannelFuture channelFuture = ctx.writeAndFlush("timeout, you will close!");

      channelFuture.addListener(new ChannelFutureListener() {

        @Override
        public void operationComplete(ChannelFuture future) throws Exception {

          future.channel().close();

        }
      });

package com.john.netty.learn.ch06.netty5.x;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;


public class Netty5HeartBeatServer {


  private int port;


  public Netty5HeartBeatServer(int port) {


     this.port = port;


  }


  public void start() throws InterruptedException {


     ServerBootstrap serverBootstrap = new ServerBootstrap();


     EventLoopGroup boss = new NioEventLoopGroup();


     EventLoopGroup workers = new NioEventLoopGroup();


     try {


       // 设置线程池
       serverBootstrap.group(boss, workers);


       // 设置socket工厂
       serverBootstrap.channel(NioServerSocketChannel.class);


       // 设置管道工厂
       serverBootstrap.childHandler(new ChannelInitializer<Channel>() {


          @Override
          protected void initChannel(Channel ch) throws Exception {
            ch.pipeline().addLast(new IdleStateHandler(5, 5, 10));
            ch.pipeline().addLast(new StringDecoder());
            ch.pipeline().addLast(new StringEncoder());
            ch.pipeline().addLast(new HeartBeatServerHandler());
          }
       });


       serverBootstrap.option(ChannelOption.SO_BACKLOG, 2048);// serverSocketchannel的设置,链接缓冲池的大小
                                          // (未完成Accept操作,等待Socket Accept)
       serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);// socketchannel的设置,维持链接的活跃,清除死链接
       serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);// socketchannel的设置,关闭延迟发送


       // 绑定端口
       ChannelFuture channelFuture = serverBootstrap.bind(port);


       System.out.println("start server " + port);


       // 等待服务端关闭
       channelFuture.channel().closeFuture().sync();


     } finally {


       boss.shutdownGracefully();


       workers.shutdownGracefully();
     }
  }


  public static void main(String[] args) throws InterruptedException {


     new Netty5HeartBeatServer(23).start();
  }


}

package com.john.netty.learn.ch06.netty5.x;


import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;


public class HeartBeatServerHandler extends SimpleChannelInboundHandler<String> {


  public HeartBeatServerHandler() {


  }


  @Override
  public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {


    if (evt instanceof IdleStateEvent) {


      channelIdle(ctx, (IdleStateEvent) evt);


      return;
    }


    super.userEventTriggered(ctx, evt);
  }


  protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {


    if (e.state() == IdleState.ALL_IDLE) {


      System.out.println("踢玩家下线!");


      ChannelFuture channelFuture = ctx.writeAndFlush("timeout, you will close!");


      channelFuture.addListener(new ChannelFutureListener() {


        @Override
        public void operationComplete(ChannelFuture future) throws Exception {


          future.channel().close();


        }
      });
    }
  }


  @Override
  protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {


    System.out.println("Read message " + msg);


    ctx.writeAndFlush("Hi " + msg);
  }


  @Override
  public void channelActive(ChannelHandlerContext ctx) throws Exception {


    System.out.println("channelActive(ChannelHandlerContext " + ctx + ")");


  }


  @Override
  public void channelInactive(ChannelHandlerContext ctx) throws Exception {


    System.out.println("channelInactive(ChannelHandlerContext " + ctx + ")");
  }


  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {


    cause.printStackTrace();
  }


}
 

 
所有源码下载 :https://download.youkuaiyun.com/download/netcobol/10308871
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值