15-Netty心跳检测机制
Netty心跳检测机制
需求
- 编写一个Netty心跳检测机制案例, 当服务器超过3秒没有读时,就提示读空闲
- 当服务器超过5秒没有写操作时, 就提示写空闲
- 实现当服务器超过7秒没有读或者写操作时, 就提示读写空闲
- 代码如下
NettyServerHertbeat
package com.dance.netty.netty.heartbeat; import com.dance.netty.netty.groupchar.NettyServerHandler; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.handler.timeout.IdleStateHandler; import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; public class NettyServerHertBeat { private final int port; public NettyServerHertBeat(int port) { this.port = port; } public void run() throws InterruptedException { NioEventLoopGroup bossGroup = new NioEventLoopGroup(1); NioEventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true) .handler(new LoggingHandler(LogLevel.INFO)) // 在BossGroup中增加一个日志处理器 日志级别为INFO .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); // IdleStateHandler 是Netty提供的处理空闲状态的处理器(这个只是检测,如果存在就会激活一个IDLEStateEvent事件) /* * 第一个: 读空闲时间, 表示多长时间没有读, 就会发送一个心跳检测包检测是否连接 * 第二个: 写空闲时间 表示多长时间没有写, 就会发送一个心跳检测包检测是否连接 * 第三个: 所有空闲时间 表示多长时间没有读写, 就会发送一个心跳检测包检测是否连接 * 第四个: 时间单位 * 文档说明: triggers on {@link IdleStateEvent} when a {@link Channel} has not performed read * ,write, or both operation for a while * 当 IdleStateEvent 触发后, 就会传递给管道的下一个handler去处理 * 通过调用(触发)下一个handler的userEventTriggered */ pipeline.addLast(new IdleStateHandler(3, 5, 7, TimeUnit.SECONDS)); // 加入一个对空闲检测进一步处理的Handler(自定义) pipeline.addLast(new NettyServerIdleStateHandler()); } }); System.out.println("netty server is starter......"); ChannelFuture sync = serverBootstrap.bind(port).sync(); sync.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { new NettyServerHertBeat(7000).run(); } }
NettyServerIdleStatHandler
package com.dance.netty.netty.heartbeat; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.timeout.IdleStateEvent; public class NettyServerIdleStateHandler extends ChannelInboundHandlerAdapter { /** * 用户事件触发器 * * @param ctx 上下文 * @param evt 事件 * @throws Exception 异常 */ @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { // 如果属于空闲事件 if (evt instanceof IdleStateEvent) { IdleStateEvent idleStateEvent = (IdleStateEvent) evt; String msg = ""; switch (idleStateEvent.state()) { // 读空闲事件 case READER_IDLE: msg = "读空闲"; break; // 写空闲事件 case WRITER_IDLE: msg = "写空闲"; break; // 读写空闲事件 case ALL_IDLE: msg = "读写空闲"; break; default: msg = "没有对应的事件"; } System.out.println(ctx.channel().remoteAddress() + "--超时事件--" + msg); } } }
客户端采用Telnet
执行结果
netty server is starter...... 一月 16, 2022 9:58:00 下午 io.netty.handler.logging.LoggingHandler channelRegistered 信息: [id: 0xd704efa3] REGISTERED 一月 16, 2022 9:58:00 下午 io.netty.handler.logging.LoggingHandler bind 信息: [id: 0xd704efa3] BIND: 0.0.0.0/0.0.0.0:7000 一月 16, 2022 9:58:00 下午 io.netty.handler.logging.LoggingHandler channelActive 信息: [id: 0xd704efa3, L:/0:0:0:0:0:0:0:0:7000] ACTIVE 一月 16, 2022 9:58:06 下午 io.netty.handler.logging.LoggingHandler channelRead 信息: [id: 0xd704efa3, L:/0:0:0:0:0:0:0:0:7000] READ: [id: 0x3f6ff8a9, L:/127.0.0.1:7000 - R:/127.0.0.1:62391] 一月 16, 2022 9:58:06 下午 io.netty.handler.logging.LoggingHandler channelReadComplete 信息: [id: 0xd704efa3, L:/0:0:0:0:0:0:0:0:7000] READ COMPLETE /127.0.0.1:62391--超时事件--读空闲 /127.0.0.1:62391--超时事件--写空闲 /127.0.0.1:62391--超时事件--读空闲 /127.0.0.1:62391--超时事件--读写空闲 /127.0.0.1:62391--超时事件--读空闲 /127.0.0.1:62391--超时事件--写空闲 /127.0.0.1:62391--超时事件--读空闲 /127.0.0.1:62391--超时事件--读写空闲 /127.0.0.1:62391--超时事件--写空闲 /127.0.0.1:62391--超时事件--读空闲 /127.0.0.1:62391--超时事件--读空闲