IdleStateHandler 空闲状态处理器,是用来检测当前Handler的ChannelRead()的空闲时间。
构造方法如下
public IdleStateHandler(
long readerIdleTime, long writerIdleTime, long allIdleTime,
TimeUnit unit) {
this(false, readerIdleTime, writerIdleTime, allIdleTime, unit);
}
四个参数如下
1)readerIdleTime:为读超时时间(即多长时间没有接受到客户端发送数据)
2)writerIdleTime:为写超时时间(即多长时间没有向客户端发送数据)
3)allIdleTime:所有类型(读或写)的超时时间
4)timeunit:超时时间类型
根据这四个参数IdleStateHandler会启动不同的定时任务,根据设定的时长去检测ChannelRead()方法是否被调用,如果没有被调用。之后则会调用后续handler的userEventTriggered方法去执行一些事情(比如断开链接)
IdleStateHandler 的channelActive方法会在客户端连接到服务端触发代码如下
public void channelActive(ChannelHandlerContext ctx) throws Exception {
initialize(ctx);
super.channelActive(ctx);
}
private void initialize(ChannelHandlerContext ctx) {
// Avoid the case where destroy() is called before scheduling timeouts.
// See: https://github.com/netty/netty/issues/143
switch (state) {
case 1:
case 2:
return;
}
state = 1;
initOutputChanged(ctx);
//记录最后读与写的时间
lastReadTime = lastWriteTime = ticksInNanos();
if (readerIdleTimeNanos > 0) {
readerIdleTimeout = schedule(ctx, new ReaderIdleTimeoutTask(ctx),
readerIdleTimeNanos, TimeUnit.NANOSECONDS);
}
if (writerIdleTimeNanos > 0) {
writerIdleTimeout = schedule(ctx, new WriterIdleTimeoutTask(ctx),
writerIdleTimeNanos, TimeUnit.NANOSECONDS);
}
if (allIdleTimeNanos > 0) {
allIdleTimeout = schedule(ctx, new AllIdleTimeoutTask(ctx),
allIdleTimeNanos, TimeUnit.NANOSECONDS);
}
}
ScheduledFuture<?> schedule(ChannelHandlerContext ctx, Runnable task, long delay, TimeUnit unit) {
return ctx.executor().schedule(task, delay, unit);
}
可以看到启动三个task去执行任务,三个task都实现了Runnable接口,那么task的run的方法是重点。
private final class ReaderIdleTimeoutTask extends AbstractIdleTask {
ReaderIdleTimeoutTask(ChannelHandlerContext ctx) {
super(ctx);
}
@Override
protected void run(ChannelHandlerContext ctx) {
long nextDelay = readerIdleTimeNanos;
if (!reading) {
//判断是否超时,当前时间-上次读的时间是否大于设置的时间
//大于则超时
nextDelay -= ticksInNanos() - lastReadTime;
}
//超时逻辑
if (nextDelay <= 0) {
// Reader is idle - set a new timeout and notify the callback.
readerIdleTimeout = schedule(ctx, this, readerIdleTimeNanos, TimeUnit.NANOSECONDS);
boolean first = firstReaderIdleEvent;
firstReaderIdleEvent = false;
try {
IdleStateEvent event = newIdleStateEvent(IdleState.READER_IDLE, first);
channelIdle(ctx, event);
} catch (Throwable t) {
ctx.fireExceptionCaught(t);
}
} else {
// Read occurred before the timeout - set a new timeout with shorter delay.
readerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
}
}
}
protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception {
//调用Pipeline中的下一个handler的userEventTriggered方法
ctx.fireUserEventTriggered(evt);
}
可以看到判断出超时时会调用下一个Handler的userEventTriggered方法去执行
如果想用这个handler必须要有两点注意:
1、因为次handler是监测的是ChannelRead方法,最好放到最开始或者前几位,千万要记得一定要传递到此handler,否则是不会监测到ChannelRead的
2、其后的handler要实现userEventTriggered方法