1.什么是心跳检测?
判断对方是否正常运行,一般采用定时发送简单的通讯包,如果在指定时间内未接收到对方响应,则判定对方已经宕掉。用于检测TCP的异常断开。
心跳包一般就是客户端发送给服务端的简单消息,如果服务端几分钟内没有收到客户端消息,则视为客户端已经断开,这个时候就主动关闭客户端的通道。
2.使用Netty实现服务端心跳检测
下面我们编写服务端代码,服务端实现以下功能:如果在N长时间内没有接受到客户端连接,则发送一段信息给客户端,并关闭其通道
* 我们创建服务端心跳检测的Handler,命名为HeartBeatHandler,并重写userEventTriggered方法
/**
* 服务端心跳检测
*/
public class HeartBeatHandler extends ChannelInboundHandlerAdapter {
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if(evt instanceof IdleStateEvent){
IdleStateEvent ise = (IdleStateEvent)evt;
// 服务端读空闲
if(ise.state().equals(IdleState.READER_IDLE)){
ctx.writeAndFlush("client reader idle, channel will close");
ctx.channel().close();
// 服务端写空闲
}else if (ise.state().equals(IdleState.WRITER_IDLE)){
ctx.write("pong message");
// 服务端读写空闲
}else if (ise.state().equals(IdleState.ALL_IDLE)){
ctx.channel().close();
}else{
// DO NOTHING
}
}
}
}
* 服务端代码,如下
public class Server {
public static void main(String[] args) {
//服务类
ServerBootstrap bootstrap = new ServerBootstrap();
//boss和worker
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
//设置线程池
bootstrap.group(boss, worker);
//设置socket工厂
bootstrap.channel(NioServerSocketChannel.class);
//设置管道工厂
bootstrap.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder());
// 主要在这里,先创建一个IdleStateHandler,10秒内没有读写则判定为空闲
ch.pipeline().addLast(new IdleStateHandler(10, 10, 10, TimeUnit.SECONDS));
// 然后执行心跳检测
ch.pipeline().addLast(new HeartBeatHandler());
}
});
//设置参数,TCP参数
bootstrap.option(ChannelOption.SO_BACKLOG, 2048);//serverSocketchannel的设置,链接缓冲池的大小
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);//socketchannel的设置,维持链接的活跃,清除死链接
bootstrap.childOption(ChannelOption.TCP_NODELAY, true);//socketchannel的设置,关闭延迟发送
//绑定端口
ChannelFuture future = bootstrap.bind(8088).sync();
System.out.println("server start...");
//等待服务端关闭
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally{
//释放资源
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
* 启动服务端并测试
启动服务端之后,我们来开启一个客户端,还是使用telnet的方式
连接到服务端之后,如果我们十秒钟不发送数据的话,则会被强制关闭连接,如下图所示
3.关于IdleStateHandler源码分析
1)IdleStateHandler结构分析
public class IdleStateHandler extends ChannelDuplexHandler {
// 对象初始化的时候初始化好这些数据
private final long readerIdleTimeNanos;
private final long writerIdleTimeNanos;
private final long allIdleTimeNanos;
// 通过构造函数可知
public IdleStateHandler(
long readerIdleTime, long writerIdleTime, long allIdleTime,
TimeUnit unit) {
if (unit == null) {
throw new NullPointerException("unit");
}
if (readerIdleTime 0) {
allIdleTimeout = loop.schedule(
new AllIdleTimeoutTask(ctx),
allIdleTimeNanos, TimeUnit.NANOSECONDS);
}
}
总结:由上可知,实现心跳检测的关键就在这个schedule上,根据用户设置的空闲时间来确定定时任务的频率。
那么,定时任务是如何做到检测的呢?我们继续来看
3)ReaderIdleTimeoutTask
源码如下:
private final class ReaderIdleTimeoutTask implements Runnable {
private final ChannelHandlerContext ctx;
ReaderIdleTimeoutTask(ChannelHandlerContext ctx) {
this.ctx = ctx;
}
@Override
public void run() {
if (!ctx.channel().isOpen()) {
return;
}
// 1.获取当前时间和最后一次读时间
long currentTime = System.nanoTime();
long lastReadTime = IdleStateHandler.this.lastReadTime;
// nextDelay即为比较用户设置的读空闲时间和 当前时间-最后一次时间
long nextDelay = readerIdleTimeNanos - (currentTime - lastReadTime);
// 2.如果nextDelay
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?