admin管理员组文章数量:1794759
Netty
欢迎微信搜索并关注“小猴子的技术笔记”公众号 私信我 领取丰富的视频学习资料!
关于心跳我们在长链接的开发中一般都是会遇到的,因为是长链接所以需要定时发送心跳保持连接的活跃。当服务端检测不到客户端的心跳之后就会释放资源,这个操作是一个很重要的操作。
如果你处理过原生socket的心跳检测机制,你会发现那是一个比较麻烦的处理。你需要起一个线程或者定时任务来不停的检测连接是否有心跳上送,如果没有心跳你就需要释放资源,关闭socket或者尝试重连机制。
Netty为我们提供了一个“IdleStateHandler”闲置状态处理器。如果在一定的时间内没有读、写或者两者都没有的操作将会被触发这个处理器的事件。
关于“IdleStateHandler”我们需要设置一些参数,一般的设置为:
public IdleStateHandler(long readerIdleTime, long writerIdleTime,long allIdleTime,TimeUnit unit) {this(false, readerIdleTime, writerIdleTime, allIdleTime, unit);
}
“readerIdleTime”:读取数据的超时时间,也就是说连接建立之后在这个readerIdleTime时间内没有读取到数据就会被触发。
“writerIdleTime”:写超时事件,也就是说在连接建立之后在writerIdleTime时间内没有往外面写任何数据。
“allIdleTime”:读写超时事件,也就是说在连接建立之后在allIdleTime时间内既没有发生读的事件,也没有发生写的事件。
“unit”:前面参数的时间单位,是以分钟啊,还是秒啊,或者是小时为单位进行一次检测数据。
如果参数设置成0的话,那么是“无效”的,也就是说netty会忽略到这个配置。接下来看看心跳检测的示例。
public class HeartBeatServer {public static void main(String[] args) {EventLoopGroup boss = new NioEventLoopGroup();EventLoopGroup worker = new NioEventLoopGroup();try {ServerBootstrap server = new ServerBootstrap();server.group(boss, worker).channel(NioServerSocketChannel.class).childHandler(new HeartBeatServerInitializer());ChannelFuture channelFuture = server.bind(9999).sync();channelFuture.channel().closeFuture().sync();} catch (Exception e) {e.printStackTrace();} finally {boss.shutdownGracefully();worker.shutdownGracefully();}}
}
public class HeartBeatServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new LineBasedFrameDecoder(1024));pipeline.addLast(new StringDecoder());pipeline.addLast(new StringEncoder());pipeline.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));pipeline.addLast(new HeartBeatServerHandler());}
}
public class HeartBeatServerHandler extends SimpleChannelInboundHandler<String> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {System.out.println("接收到信息: " + msg);}@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {IdleStateEvent event = (IdleStateEvent) evt;switch (event.state()) {case READER_IDLE:System.out.println("读空闲");break;case WRITER_IDLE:System.out.println("写空闲");break;case ALL_IDLE:System.out.println("读写空闲");break;default:throw new IllegalStateException("非法状态!");}}
}
假设我们写一个客户端不进行数据的发送,看看会触发什么效果:
public class HeartBeatClient {public static void main(String[] args) {EventLoopGroup worker = new NioEventLoopGroup();try {Bootstrap client = new Bootstrap();client.group(worker).channel(NioSocketChannel.class).handler(new HeartBeatClientInitializer());Channel channel = client.connect("localhost", 9999).sync().channel();channel.closeFuture().sync();} catch (Exception e) {e.printStackTrace();} finally {worker.shutdownGracefully();}}
}
public class HeartBeatClientInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new LineBasedFrameDecoder(1024));pipeline.addLast(new StringEncoder());pipeline.addLast(new StringDecoder());pipeline.addLast(new HeartBeatClientHandler());}
}
public class HeartBeatClientHandler extends SimpleChannelInboundHandler<String> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {}
}
启动服务端和客户端,等过一段时间你会发现:
读空闲
读空闲
读空闲
也许你会疑问,被触发了之后该怎么办呢?其实,想怎么办就怎办!也许你已经发现了,在事件被触发的方法中有一个比较重要的“ChannelHandlerContext”。这个“ChannelHandlerContext”是连接ChannelHandler和ChannelPipeline的重要上下文,有了它你就可以对channel进行操作了!
那么将之前的代码进行一下修改,没有读取到数据就断开连接。
public class HeartBeatServerHandler extends SimpleChannelInboundHandler<String> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {System.out.println("接收到信息: " + msg);}@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {IdleStateEvent event = (IdleStateEvent) evt;switch (event.state()) {case READER_IDLE:System.out.println("读空闲");ctx.channel().close();break;case WRITER_IDLE:System.out.println("写空闲");break;case ALL_IDLE:System.out.println("读写空闲");break;default:throw new IllegalStateException("非法状态!");}}
}
你会发现就添加了一行代码。
ctx.channel().close();
再来试着运行一下服务端和客户端:都运行的时候可以到两个进程在运行
等过了5秒服务端打印出一句话之后就不会再继续打印了。
再看看进程就剩一个客户端了。
其实不仅如此,你完全可以结合业务对心跳检测信息做出处理。因为你已经拿到了它对应的“ChannelHandlerContext”,你可以利用它写数据,广播数据,关闭连接等操作。客户端也可以根据服务端上送的心跳进行重连等操作!
欢迎微信搜索并关注“小猴子的技术笔记”公众号 私信我 领取丰富的视频学习资料!
本文标签: Netty
版权声明:本文标题:Netty 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1692875352a216950.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论