网络链接中,处理Idle事件是很常见的,通常状况下,客户端与服务端在指定时间内没有任何读写请求,就会认为链接是idle的。此时,客户端须要向服务端发送ping消息,来维持服务端与客户端的连接。那么怎么判断客户端在指定时间里没有任何读写请求呢?netty中为咱们提供一个特别好用的IdleStateHandler来干这个苦差事!请看下面代码:java
public class EchoClient { private final static int readerIdleTimeSeconds = 40;//读操做空闲30秒 private final static int writerIdleTimeSeconds = 50;//写操做空闲60秒 private final static int allIdleTimeSeconds = 100;//读写所有空闲100秒 public void connect(int port, String host) throws Exception { // 配置客户端NIO线程组 EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes()); ch.pipeline().addLast("idleStateHandler", new IdleStateHandler(readerIdleTimeSeconds, writerIdleTimeSeconds,allIdleTimeSeconds)); ch.pipeline().addLast( new DelimiterBasedFrameDecoder(1024, delimiter)); ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new EchoClientHandler()); } }); // 发起异步链接操做 ChannelFuture f = b.connect(host, port).sync(); // 当代客户端链路关闭 f.channel().closeFuture().sync(); } finally { // 优雅退出,释放NIO线程组 group.shutdownGracefully(); } } /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { int port = 8080; if (args != null && args.length > 0) { try { port = Integer.valueOf(args[0]); } catch (NumberFormatException e) { // 采用默认值 } } new EchoClient().connect(port, "127.0.0.1"); } }
在netty的客户端中添加:网络
ch.pipeline().addLast("idleStateHandler", new IdleStateHandler(readerIdleTimeSeconds, writerIdleTimeSeconds,allIdleTimeSeconds));
这个处理器,它的做用就是用来检测客户端的读取超时的,该类的第一个参数是指定读操做空闲秒数,第二个参数是指定写操做的空闲秒数,第三个参数是指定读写空闲秒数,当有操做操做超出指定空闲秒数时,便会触发UserEventTriggered事件。因此咱们只须要在本身的handler中截获该事件,而后发起相应的操做便可(好比说发起ping操做)。如下是咱们自定义的handler中的代码:异步
public class EchoClientHandler extends ChannelHandlerAdapter { private int counter; static final String ECHO_REQ = "Hi, Lilinfeng. Welcome to Netty.$_"; public EchoClientHandler() { } @Override public void channelActive(ChannelHandlerContext ctx) { for (int i = 0; i < 10; i++) { ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes())); } } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("This is " + ++counter + " times receive server : [" + msg + "]"); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) { IdleStateEvent event = (IdleStateEvent) evt; if (event.state() == IdleState.READER_IDLE) System.out.println("read idle"); else if (event.state() == IdleState.WRITER_IDLE) System.out.println("write idle"); else if (event.state() == IdleState.ALL_IDLE) System.out.println("all idle"); } }
这里,咱们重点看从新的 userEventTriggered方法:ide
首先,判断evt事件是否是IdleStateEvent事件;oop
而后,继续判断是读空闲事件仍是写空闲事件仍是读写空闲事件;
线程
最后,根据不一样事件类型发起相应的操做
netty
好了,如今回到咱们的主题,咱们的目的是在客户端在写空闲超时时,客户端主动发起一次平操做,因此咱们只须要判断写空闲超时,发起ping操做便可!code