網絡鏈接中,處理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