netty中使用IdleStateHandler来发起心跳

网络链接中,处理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

相关文章
相关标签/搜索