Netty 超时机制及心跳程序实现

本文同步至 http://www.waylau.com/netty-time-out-and-heartbeat/

本文介绍了 Netty 超时机制的原理,以及如何在连接闲置时发送一个心跳来维持连接。

Netty 超时机制的介绍

Netty 的超时类型 IdleState 主要分为:

  • ALL_IDLE : 一段时间内没有数据接收或者发送
  • READER_IDLE : 一段时间内没有数据接收
  • WRITER_IDLE : 一段时间内没有数据发送

在 Netty 的 timeout 包下,主要类有:

  • IdleStateEvent : 超时的事件
  • IdleStateHandler : 超时状态处理
  • ReadTimeoutHandler : 读超时状态处理
  • WriteTimeoutHandler : 写超时状态处理

其中 IdleStateHandler 包含了读\写超时状态处理,比如

1private static final int READ_IDEL_TIME_OUT = 4; // 读超时 2private static final int WRITE_IDEL_TIME_OUT = 5;// 写超时 3private static final int ALL_IDEL_TIME_OUT = 7; // 所有超时 4 5new IdleStateHandler(READ_IDEL_TIME_OUT, 6 WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));

上述例子,在 IdleStateHandler 中定义了读超时的时间是 4 秒, 写超时的时间是 5 秒,其他所有的超时时间是 7 秒。

应用 IdleStateHandler

既然 IdleStateHandler 包括了读\写超时状态处理,那么很多时候 ReadTimeoutHandler 、 WriteTimeoutHandler 都可以不用使用。定义另一个名为 HeartbeatHandlerInitializer 的 ChannelInitializer :

1public class HeartbeatHandlerInitializer extends ChannelInitializer<Channel> { 2 3 private static final int READ_IDEL_TIME_OUT = 4; // 读超时 4 private static final int WRITE_IDEL_TIME_OUT = 5;// 写超时 5 private static final int ALL_IDEL_TIME_OUT = 7; // 所有超时 6 7 @Override 8 protected void initChannel(Channel ch) throws Exception { 9 ChannelPipeline pipeline = ch.pipeline(); 10 pipeline.addLast(new IdleStateHandler(READ_IDEL_TIME_OUT, 11 WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS)); // 1 12 pipeline.addLast(new HeartbeatServerHandler()); // 2 13 } 14}
  1. 使用了 IdleStateHandler ,分别设置了读、写超时的时间
  2. 定义了一个 HeartbeatServerHandler 处理器,用来处理超时时,发送心跳

定义了一个心跳处理器

1public class HeartbeatServerHandler extends ChannelInboundHandlerAdapter { 2 3 // Return a unreleasable view on the given ByteBuf 4 // which will just ignore release and retain calls. 5 private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled 6 .unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat", 7 CharsetUtil.UTF_8)); // 1 8 9 @Override 10 public void userEventTriggered(ChannelHandlerContext ctx, Object evt) 11 throws Exception { 12 13 if (evt instanceof IdleStateEvent) { // 2 14 IdleStateEvent event = (IdleStateEvent) evt; 15 String type = ""; 16 if (event.state() == IdleState.READER_IDLE) { 17 type = "read idle"; 18 } else if (event.state() == IdleState.WRITER_IDLE) { 19 type = "write idle"; 20 } else if (event.state() == IdleState.ALL_IDLE) { 21 type = "all idle"; 22 } 23 24 ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()).addListener( 25 ChannelFutureListener.CLOSE_ON_FAILURE); // 3 26 27 System.out.println( ctx.channel().remoteAddress()+"超时类型:" + type); 28 } else { 29 super.userEventTriggered(ctx, evt); 30 } 31 } 32}
  1. 定义了心跳时,要发送的内容
  2. 判断是否是 IdleStateEvent 事件,是则处理
  3. 将心跳内容发送给客户端

服务器

服务器代码比较简单,启动后侦听 8082 端口

1public final class HeartbeatServer { 2 3 static final int PORT = 8082; 4 5 public static void main(String[] args) throws Exception { 6 7 // Configure the server. 8 EventLoopGroup bossGroup = new NioEventLoopGroup(1); 9 EventLoopGroup workerGroup = new NioEventLoopGroup(); 10 try { 11 ServerBootstrap b = new ServerBootstrap(); 12 b.group(bossGroup, workerGroup) 13 .channel(NioServerSocketChannel.class) 14 .option(ChannelOption.SO_BACKLOG, 100) 15 .handler(new LoggingHandler(LogLevel.INFO)) 16 .childHandler(new HeartbeatHandlerInitializer()); 17 18 // Start the server. 19 ChannelFuture f = b.bind(PORT).sync(); 20 21 // Wait until the server socket is closed. 22 f.channel().closeFuture().sync(); 23 } finally { 24 // Shut down all event loops to terminate all threads. 25 bossGroup.shutdownGracefully(); 26 workerGroup.shutdownGracefully(); 27 } 28 } 29}

客户端测试

客户端用操作系统自带的 Telnet 程序即可:

telnet 127.0.0.1 8082

效果

源码

https://github.com/waylau/netty-4-user-guide-demosheartbeat

参考

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

swap空间的增减方法

(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap