Netty 超時機制及心跳程序實現

本文介紹了 Netty 超時機制的原理,以及如何在鏈接閒置時發送一個心跳來維持鏈接。java

Netty 超時機制的介紹

Netty 的超時類型 IdleState 主要分爲:git

  • ALL_IDLE : 一段時間內沒有數據接收或者發送
  • READER_IDLE : 一段時間內沒有數據接收
  • WRITER_IDLE : 一段時間內沒有數據發送

在 Netty 的 timeout 包下,主要類有:github

  • IdleStateEvent : 超時的事件
  • IdleStateHandler : 超時狀態處理
  • ReadTimeoutHandler : 讀超時狀態處理
  • WriteTimeoutHandler : 寫超時狀態處理

其中 IdleStateHandler 包含了讀\寫超時狀態處理,好比服務器

private static final int READ_IDEL_TIME_OUT = 4; // 讀超時

private static final int WRITE_IDEL_TIME_OUT = 5;// 寫超時

private static final int ALL_IDEL_TIME_OUT = 7; // 全部超時


new IdleStateHandler(READ_IDEL_TIME_OUT,

            WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));

上述例子,在 IdleStateHandler 中定義了讀超時的時間是 4 秒, 寫超時的時間是 5 秒,其餘全部的超時時間是 7 秒。socket

應用 IdleStateHandler

既然 IdleStateHandler 包括了讀\寫超時狀態處理,那麼不少時候 ReadTimeoutHandler 、 WriteTimeoutHandler 均可以不用使用。定義另外一個名爲 HeartbeatHandlerInitializer 的 ChannelInitializer :ide

public class HeartbeatHandlerInitializer extends ChannelInitializer<Channel> {



    private static final int READ_IDEL_TIME_OUT = 4; // 讀超時

    private static final int WRITE_IDEL_TIME_OUT = 5;// 寫超時

    private static final int ALL_IDEL_TIME_OUT = 7; // 全部超時


    @Override

    protected void initChannel(Channel ch) throws Exception {

        ChannelPipeline pipeline = ch.pipeline();

        pipeline.addLast(new IdleStateHandler(READ_IDEL_TIME_OUT,

                WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS)); // 1

        pipeline.addLast(new HeartbeatServerHandler()); // 2

    }

}
  1. 使用了 IdleStateHandler ,分別設置了讀、寫超時的時間
  2. 定義了一個 HeartbeatServerHandler 處理器,用來處理超時時,發送心跳

定義了一個心跳處理器

public class HeartbeatServerHandler extends ChannelInboundHandlerAdapter {


    // Return a unreleasable view on the given ByteBuf

    // which will just ignore release and retain calls.

    private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled

            .unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat",

                    CharsetUtil.UTF_8));  // 1


    @Override

    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)

            throws Exception {



        if (evt instanceof IdleStateEvent) {  // 2

            IdleStateEvent event = (IdleStateEvent) evt; 

            String type = "";

            if (event.state() == IdleState.READER_IDLE) {

                type = "read idle";

            } else if (event.state() == IdleState.WRITER_IDLE) {

                type = "write idle";

            } else if (event.state() == IdleState.ALL_IDLE) {

                type = "all idle";

            }


            ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()).addListener(

                    ChannelFutureListener.CLOSE_ON_FAILURE);  // 3


            System.out.println( ctx.channel().remoteAddress()+"超時類型:" + type);

        } else {

            super.userEventTriggered(ctx, evt);

        }

    }

}
  1. 定義了心跳時,要發送的內容
  2. 判斷是不是 IdleStateEvent 事件,是則處理
  3. 將心跳內容發送給客戶端

服務器

服務器代碼比較簡單,啓動後偵聽 8082 端口oop

public final class HeartbeatServer {



    static final int PORT = 8082;



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



        // Configure the server.

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);

        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {

            ServerBootstrap b = new ServerBootstrap();

            b.group(bossGroup, workerGroup)

             .channel(NioServerSocketChannel.class)

             .option(ChannelOption.SO_BACKLOG, 100)

             .handler(new LoggingHandler(LogLevel.INFO))

             .childHandler(new HeartbeatHandlerInitializer());



            // Start the server.

            ChannelFuture f = b.bind(PORT).sync();



            // Wait until the server socket is closed.

            f.channel().closeFuture().sync();

        } finally {

            // Shut down all event loops to terminate all threads.

            bossGroup.shutdownGracefully();

            workerGroup.shutdownGracefully();

        }

    }

}

客戶端用操做系統自帶的 Telnet 程序便可:客戶端測試

telnet 127.0.0.1 8082


效果

源碼

見 https://github.com/waylau/netty-4-user-guide-demos 中 heartbeat包測試

參考

  • Netty 4.x 用戶指南 https://github.com/waylau/netty-4-user-guide
  • Netty 實戰(精髓) https://github.com/waylau/essential-netty-in-action
相關文章
相關標籤/搜索