• Netty(三):IdleStateHandler源码解析


    IdleStateHandler是Netty为我们提供的检测连接有效性的处理器,一共有读空闲,写空闲,读/写空闲三种监测机制。

    将其添加到我们的ChannelPipline中,便可以用来检测空闲。

    先通过一段代码来学习下IdleStateHandler的用法:

    ConnectStateHandler:(负责监测通道的各种状态并处理空闲事件IdleStateEvent)

     1 package com.insaneXs.netty.idlestate;
     2 
     3 import io.netty.channel.ChannelHandlerContext;
     4 import io.netty.channel.ChannelInboundHandlerAdapter;
     5 import io.netty.handler.timeout.IdleState;
     6 import io.netty.handler.timeout.IdleStateEvent;
     7 
     8 public class ConnectStateHandler extends ChannelInboundHandlerAdapter {
     9 
    10     public ConnectStateHandler() {
    11         super();
    12     }
    13 
    14     @Override
    15     public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    16         System.out.println("Channel Register");
    17         super.channelRegistered(ctx);
    18     }
    19 
    20     @Override
    21     public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
    22         System.out.println("Channel Unregister");
    23         super.channelUnregistered(ctx);
    24     }
    25 
    26     @Override
    27     public void channelActive(ChannelHandlerContext ctx) throws Exception {
    28         System.out.println("Channel Active");
    29         super.channelActive(ctx);
    30     }
    31 
    32     @Override
    33     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    34         System.out.println("Channel Inactive");
    35         super.channelInactive(ctx);
    36     }
    37 
    38     @Override
    39     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    40         System.out.println("Channel Read");
    41         super.channelRead(ctx, msg);
    42     }
    43 
    44     @Override
    45     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    46         System.out.println("Channel Read Complete");
    47         super.channelReadComplete(ctx);
    48     }
    49 
    50     @Override
    51     public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    52         if(evt instanceof IdleStateEvent){
    53             if(((IdleStateEvent)evt).state().equals(IdleState.READER_IDLE)){
    54                 System.out.println("Read Idle");
    55                 ctx.close();
    56             }
    57         }else{
    58             super.userEventTriggered(ctx, evt);
    59         }
    60     }
    61 
    62     @Override
    63     public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
    64         super.channelWritabilityChanged(ctx);
    65     }
    66 
    67     @Override
    68     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    69         super.exceptionCaught(ctx, cause);
    70     }
    71 }

     服务器代码:

     1 package com.insaneXs.netty.idlestate;
     2 
     3 import io.netty.bootstrap.ServerBootstrap;
     4 import io.netty.channel.ChannelInitializer;
     5 import io.netty.channel.ChannelPipeline;
     6 import io.netty.channel.EventLoopGroup;
     7 import io.netty.channel.nio.NioEventLoopGroup;
     8 import io.netty.channel.socket.nio.NioServerSocketChannel;
     9 import io.netty.channel.socket.nio.NioSocketChannel;
    10 import io.netty.handler.timeout.IdleStateHandler;
    11 
    12 public class NettyServer {
    13 
    14     public static void main(String[] args){
    15         EventLoopGroup boss = new NioEventLoopGroup(1);
    16         EventLoopGroup work = new NioEventLoopGroup(4);
    17 
    18         try {
    19         ServerBootstrap bootstrap = new ServerBootstrap();
    20         bootstrap.group(boss,work)
    21                 .channel(NioServerSocketChannel.class)
    22                 .childHandler(new ChannelInitializer<NioSocketChannel>() {
    23                     @Override
    24                     protected void initChannel(NioSocketChannel ch) throws Exception {
    25                         ChannelPipeline pipeline = ch.pipeline();
    26 
    27                         pipeline.addLast(new IdleStateHandler(30, 0, 0));
    28                         pipeline.addLast(new ConnectStateHandler());
    29                     }
    30                 });
    31 
    32 
    33             bootstrap.bind(8322).sync().channel().closeFuture().sync();
    34         } catch (InterruptedException e) {
    35             e.printStackTrace();
    36         }
    37     }
    38 }

    测试客户端代码:

     1 package com.insaneXs.netty.common;
     2 
     3 import io.netty.bootstrap.Bootstrap;
     4 import io.netty.channel.ChannelInboundHandlerAdapter;
     5 import io.netty.channel.EventLoopGroup;
     6 import io.netty.channel.nio.NioEventLoopGroup;
     7 import io.netty.channel.socket.nio.NioSocketChannel;
     8 
     9 public class CommonNettyClient {
    10 
    11     public static void main(String[] args){
    12         EventLoopGroup group = new NioEventLoopGroup();
    13 
    14         Bootstrap bootstrap = new Bootstrap();
    15         bootstrap.group(group)
    16                 .channel(NioSocketChannel.class)
    17                 .remoteAddress("localhost", 8322)
    18                 .handler(new ChannelInboundHandlerAdapter());
    19 
    20         bootstrap.connect();
    21     }
    22 }

    测试结果:

     

     从上面的输出中我们可以看到Channel的状态变化:

    1.连接建立时会从register -> active,

    2.当读空闲时,我们产生了一个空闲事件,当ConnectStateHandler捕获这个事件后,会主动断开连接。 

    3.断开时则是从inactive -> unregister。

    接下来我们学习下IdleStateHandler源码:

      1 /*
      2  * Copyright 2012 The Netty Project
      3  *
      4  * The Netty Project licenses this file to you under the Apache License,
      5  * version 2.0 (the "License"); you may not use this file except in compliance
      6  * with the License. You may obtain a copy of the License at:
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations
     14  * under the License.
     15  */
     16 package io.netty.handler.timeout;
     17 
     18 import io.netty.bootstrap.ServerBootstrap;
     19 import io.netty.channel.Channel;
     20 import io.netty.channel.Channel.Unsafe;
     21 import io.netty.channel.ChannelDuplexHandler;
     22 import io.netty.channel.ChannelFuture;
     23 import io.netty.channel.ChannelFutureListener;
     24 import io.netty.channel.ChannelHandlerContext;
     25 import io.netty.channel.ChannelInitializer;
     26 import io.netty.channel.ChannelOutboundBuffer;
     27 import io.netty.channel.ChannelPromise;
     28 
     29 import java.util.concurrent.ScheduledFuture;
     30 import java.util.concurrent.TimeUnit;
     31 
     32 /
     33  *
     34  * @see ReadTimeoutHandler
     35  * @see WriteTimeoutHandler
     36  */
     37 public class IdleStateHandler extends ChannelDuplexHandler {
     38     private static final long MIN_TIMEOUT_NANOS = TimeUnit.MILLISECONDS.toNanos(1);
     39 
     40     // Not create a new ChannelFutureListener per write operation to reduce GC pressure.
     41     private final ChannelFutureListener writeListener = new ChannelFutureListener() {
     42         @Override
     43         public void operationComplete(ChannelFuture future) throws Exception {
     44             lastWriteTime = ticksInNanos();
     45             firstWriterIdleEvent = firstAllIdleEvent = true;
     46         }
     47     };
     48 
     49     //是否观察出站情况;默认false
     50     private final boolean observeOutput;
     51     
     52     /*******三种超时情况管理*********/
     53     //读超时时间
     54     private final long readerIdleTimeNanos;
     55     //写超时时间
     56     private final long writerIdleTimeNanos;
     57     //读或写超时时间
     58     private final long allIdleTimeNanos;
     59 
     60     //读空闲定时任务,验证是否读超时
     61     private ScheduledFuture<?> readerIdleTimeout;
     62     //最后一次读时间
     63     private long lastReadTime;
     64     //是否第一次读超时
     65     private boolean firstReaderIdleEvent = true;
     66 
     67     //写空闲定时任务,验证是否写超时
     68     private ScheduledFuture<?> writerIdleTimeout;
     69     //最后一次写超时
     70     private long lastWriteTime;
     71     //是否第一次写超时
     72     private boolean firstWriterIdleEvent = true;
     73 
     74     //读或写超时定时任务
     75     private ScheduledFuture<?> allIdleTimeout;
     76     //是否读或写超时
     77     private boolean firstAllIdleEvent = true;
     78 
     79     //处理器状态: 0-无状态, 1-初始化, 2-销毁
     80     private byte state; // 0 - none, 1 - initialized, 2 - destroyed
     81     //读状态标志
     82     private boolean reading;
     83 
     84     /****用于观察输出情况*****/
     85     private long lastChangeCheckTimeStamp;
     86     private int lastMessageHashCode;
     87     private long lastPendingWriteBytes;
     88 
     89     //设置超时时间;默认单位为秒
     90     public IdleStateHandler(
     91             int readerIdleTimeSeconds,
     92             int writerIdleTimeSeconds,
     93             int allIdleTimeSeconds) {
     94 
     95         this(readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds,
     96              TimeUnit.SECONDS);
     97     }
     98 
     99     //设置三种情况超时时间与时间单位
    100     public IdleStateHandler(
    101             long readerIdleTime, long writerIdleTime, long allIdleTime,
    102             TimeUnit unit) {
    103         this(false, readerIdleTime, writerIdleTime, allIdleTime, unit);
    104     }
    105 
    106     //设置是否观察输出情况,三种情况超时时间以及时间单位
    107     public IdleStateHandler(boolean observeOutput,
    108             long readerIdleTime, long writerIdleTime, long allIdleTime,
    109             TimeUnit unit) {
    110         if (unit == null) {
    111             throw new NullPointerException("unit");
    112         }
    113 
    114         this.observeOutput = observeOutput;
    115 
    116         if (readerIdleTime <= 0) {
    117             readerIdleTimeNanos = 0;
    118         } else {
    119             readerIdleTimeNanos = Math.max(unit.toNanos(readerIdleTime), MIN_TIMEOUT_NANOS);
    120         }
    121         if (writerIdleTime <= 0) {
    122             writerIdleTimeNanos = 0;
    123         } else {
    124             writerIdleTimeNanos = Math.max(unit.toNanos(writerIdleTime), MIN_TIMEOUT_NANOS);
    125         }
    126         if (allIdleTime <= 0) {
    127             allIdleTimeNanos = 0;
    128         } else {
    129             allIdleTimeNanos = Math.max(unit.toNanos(allIdleTime), MIN_TIMEOUT_NANOS);
    130         }
    131     }
    132 
    133     /************将时间转换成毫秒级***************/
    134     public long getReaderIdleTimeInMillis() {
    135         return TimeUnit.NANOSECONDS.toMillis(readerIdleTimeNanos);
    136     }
    137 
    138     
    139     public long getWriterIdleTimeInMillis() {
    140         return TimeUnit.NANOSECONDS.toMillis(writerIdleTimeNanos);
    141     }
    142 
    143     
    144     public long getAllIdleTimeInMillis() {
    145         return TimeUnit.NANOSECONDS.toMillis(allIdleTimeNanos);
    146     }
    147 
    148     //当处理器被添加时,视情况决定是否初始化
    149     @Override
    150     public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    151         if (ctx.channel().isActive() && ctx.channel().isRegistered()) {
    152             //判断channel是否已经激活和注册,避免
    153             initialize(ctx);
    154         } else {
    155             // channelActive() event has not been fired yet.  this.channelActive() will be invoked
    156             // and initialization will occur there.
    157         }
    158     }
    159 
    160     //移除时,调用destroy销毁
    161     @Override
    162     public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
    163         destroy();
    164     }
    165 
    166     //当通道被注册时,视情况决定是否初始化
    167     @Override
    168     public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    169         // Initialize early if channel is active already.
    170         if (ctx.channel().isActive()) {
    171             initialize(ctx);
    172         }
    173         super.channelRegistered(ctx);
    174     }
    175 
    176     //当通道激活时,初始化
    177     @Override
    178     public void channelActive(ChannelHandlerContext ctx) throws Exception {
    179         // This method will be invoked only if this handler was added
    180         // before channelActive() event is fired.  If a user adds this handler
    181         // after the channelActive() event, initialize() will be called by beforeAdd().
    182         initialize(ctx);
    183         super.channelActive(ctx);
    184     }
    185 
    186     //通道不活跃时,调用destroy销毁
    187     @Override
    188     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    189         destroy();
    190         super.channelInactive(ctx);
    191     }
    192 
    193     //读事件
    194     @Override
    195     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    196         //开启了读空闲监测 或 读写空闲检测
    197         if (readerIdleTimeNanos > 0 || allIdleTimeNanos > 0) {
    198             //修改为正在读,并重置首次读写事件的标志位为true
    199             reading = true;
    200             firstReaderIdleEvent = firstAllIdleEvent = true;
    201         }
    202         ctx.fireChannelRead(msg);
    203     }
    204 
    205     //读完成
    206     @Override
    207     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    208         //如果开启了 读/读写标志 且 正在读
    209         if ((readerIdleTimeNanos > 0 || allIdleTimeNanos > 0) && reading) {
    210             //修改最后一次读取时间,重置正在读标识
    211             lastReadTime = ticksInNanos();
    212             reading = false;
    213         }
    214         ctx.fireChannelReadComplete();
    215     }
    216 
    217     @Override
    218     public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    219         //如果开启了 写/读写标志
    220         if (writerIdleTimeNanos > 0 || allIdleTimeNanos > 0) {
    221             ctx.write(msg, promise.unvoid()).addListener(writeListener);
    222         } else {
    223             ctx.write(msg, promise);
    224         }
    225     }
    226 
    227     //初始化
    228     private void initialize(ChannelHandlerContext ctx) {
    229         //判断状态避免重复初始化
    230         switch (state) {
    231         case 1:
    232         case 2:
    233             return;
    234         }
    235 
    236         state = 1;
    237         //观察输出情况
    238         initOutputChanged(ctx);
    239 
    240         //初始化最后一次读写时间
    241         lastReadTime = lastWriteTime = ticksInNanos();
    242 
    243         //根据超时时间,判断是否开启超时监测
    244         if (readerIdleTimeNanos > 0) {
    245             readerIdleTimeout = schedule(ctx, new ReaderIdleTimeoutTask(ctx),
    246                     readerIdleTimeNanos, TimeUnit.NANOSECONDS);
    247         }
    248         if (writerIdleTimeNanos > 0) {
    249             writerIdleTimeout = schedule(ctx, new WriterIdleTimeoutTask(ctx),
    250                     writerIdleTimeNanos, TimeUnit.NANOSECONDS);
    251         }
    252         if (allIdleTimeNanos > 0) {
    253             allIdleTimeout = schedule(ctx, new AllIdleTimeoutTask(ctx),
    254                     allIdleTimeNanos, TimeUnit.NANOSECONDS);
    255         }
    256     }
    257 
    258     /**
    259      * This method is visible for testing!
    260      */
    261     long ticksInNanos() {
    262         return System.nanoTime();
    263     }
    264 
    265     /**
    266      * This method is visible for testing!
    267      */
    268     ScheduledFuture<?> schedule(ChannelHandlerContext ctx, Runnable task, long delay, TimeUnit unit) {
    269         return ctx.executor().schedule(task, delay, unit);
    270     }
    271 
    272     //销毁
    273     private void destroy() {
    274         //更改状态 取消定时器
    275         state = 2;
    276 
    277         if (readerIdleTimeout != null) {
    278             readerIdleTimeout.cancel(false);
    279             readerIdleTimeout = null;
    280         }
    281         if (writerIdleTimeout != null) {
    282             writerIdleTimeout.cancel(false);
    283             writerIdleTimeout = null;
    284         }
    285         if (allIdleTimeout != null) {
    286             allIdleTimeout.cancel(false);
    287             allIdleTimeout = null;
    288         }
    289     }
    290 
    291     /**
    292      * Is called when an {@link IdleStateEvent} should be fired. This implementation calls
    293      * {@link ChannelHandlerContext#fireUserEventTriggered(Object)}.
    294      */
    295     protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception {
    296         ctx.fireUserEventTriggered(evt);
    297     }
    298 
    299     /**
    300      * Returns a {@link IdleStateEvent}.
    301      */
    302     protected IdleStateEvent newIdleStateEvent(IdleState state, boolean first) {
    303         switch (state) {
    304             case ALL_IDLE:
    305                 return first ? IdleStateEvent.FIRST_ALL_IDLE_STATE_EVENT : IdleStateEvent.ALL_IDLE_STATE_EVENT;
    306             case READER_IDLE:
    307                 return first ? IdleStateEvent.FIRST_READER_IDLE_STATE_EVENT : IdleStateEvent.READER_IDLE_STATE_EVENT;
    308             case WRITER_IDLE:
    309                 return first ? IdleStateEvent.FIRST_WRITER_IDLE_STATE_EVENT : IdleStateEvent.WRITER_IDLE_STATE_EVENT;
    310             default:
    311                 throw new IllegalArgumentException("Unhandled: state=" + state + ", first=" + first);
    312         }
    313     }
    314 
    315     /**
    316      * @see #hasOutputChanged(ChannelHandlerContext, boolean)
    317      */
    318     private void initOutputChanged(ChannelHandlerContext ctx) {
    319         if (observeOutput) {
    320             Channel channel = ctx.channel();
    321             Unsafe unsafe = channel.unsafe();
    322             ChannelOutboundBuffer buf = unsafe.outboundBuffer();
    323             //初始化消息内容的HashCode和byte
    324             if (buf != null) {
    325                 lastMessageHashCode = System.identityHashCode(buf.current());
    326                 lastPendingWriteBytes = buf.totalPendingWriteBytes();
    327             }
    328         }
    329     }
    330 
    331     //判断输出是否有变化
    332     private boolean hasOutputChanged(ChannelHandlerContext ctx, boolean first) {
    333         if (observeOutput) {
    334 
    335             // We can take this shortcut if the ChannelPromises that got passed into write()
    336             // appear to complete. It indicates "change" on message level and we simply assume
    337             // that there's change happening on byte level. If the user doesn't observe channel
    338             // writability events then they'll eventually OOME and there's clearly a different
    339             // problem and idleness is least of their concerns.
    340             if (lastChangeCheckTimeStamp != lastWriteTime) {
    341                 lastChangeCheckTimeStamp = lastWriteTime;
    342 
    343                 // But this applies only if it's the non-first call.
    344                 if (!first) {
    345                     return true;
    346                 }
    347             }
    348 
    349             Channel channel = ctx.channel();
    350             Unsafe unsafe = channel.unsafe();
    351             ChannelOutboundBuffer buf = unsafe.outboundBuffer();
    352 
    353             if (buf != null) {
    354                 int messageHashCode = System.identityHashCode(buf.current());
    355                 long pendingWriteBytes = buf.totalPendingWriteBytes();
    356 
    357                 if (messageHashCode != lastMessageHashCode || pendingWriteBytes != lastPendingWriteBytes) {
    358                     lastMessageHashCode = messageHashCode;
    359                     lastPendingWriteBytes = pendingWriteBytes;
    360 
    361                     if (!first) {
    362                         return true;
    363                     }
    364                 }
    365             }
    366         }
    367 
    368         return false;
    369     }
    370 
    371     //监测任务的父类
    372     private abstract static class AbstractIdleTask implements Runnable {
    373 
    374         private final ChannelHandlerContext ctx;
    375 
    376         AbstractIdleTask(ChannelHandlerContext ctx) {
    377             this.ctx = ctx;
    378         }
    379 
    380         @Override
    381         public void run() {
    382             if (!ctx.channel().isOpen()) {
    383                 return;
    384             }
    385 
    386             run(ctx);
    387         }
    388 
    389         protected abstract void run(ChannelHandlerContext ctx);
    390     }
    391 
    392     //读监测定时任务
    393     private final class ReaderIdleTimeoutTask extends AbstractIdleTask {
    394 
    395         ReaderIdleTimeoutTask(ChannelHandlerContext ctx) {
    396             super(ctx);
    397         }
    398 
    399         @Override
    400         protected void run(ChannelHandlerContext ctx) {
    401             long nextDelay = readerIdleTimeNanos;
    402             if (!reading) {//不在读的过程中
    403                 //计算是否超时
    404                 nextDelay -= ticksInNanos() - lastReadTime;
    405             }
    406 
    407             if (nextDelay <= 0) {//已经超时
    408                 //下次空闲监测
    409                 readerIdleTimeout = schedule(ctx, this, readerIdleTimeNanos, TimeUnit.NANOSECONDS);
    410 
    411                 boolean first = firstReaderIdleEvent;
    412                 firstReaderIdleEvent = false;
    413 
    414                 try {
    415                     //出发读超时事件
    416                     IdleStateEvent event = newIdleStateEvent(IdleState.READER_IDLE, first);
    417                     channelIdle(ctx, event);
    418                 } catch (Throwable t) {
    419                     ctx.fireExceptionCaught(t);
    420                 }
    421             } else {
    422                 // Read occurred before the timeout - set a new timeout with shorter delay.
    423                 readerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
    424             }
    425         }
    426     }
    427 
    428     //写监测定时任务
    429     private final class WriterIdleTimeoutTask extends AbstractIdleTask {
    430 
    431         WriterIdleTimeoutTask(ChannelHandlerContext ctx) {
    432             super(ctx);
    433         }
    434 
    435         @Override
    436         protected void run(ChannelHandlerContext ctx) {
    437 
    438             long lastWriteTime = IdleStateHandler.this.lastWriteTime;
    439             long nextDelay = writerIdleTimeNanos - (ticksInNanos() - lastWriteTime);
    440             if (nextDelay <= 0) {//写超时
    441                 //下一次超时检查时间 
    442                 writerIdleTimeout = schedule(ctx, this, writerIdleTimeNanos, TimeUnit.NANOSECONDS);
    443 
    444                 boolean first = firstWriterIdleEvent;
    445                 firstWriterIdleEvent = false;
    446 
    447                 try {
    448                     //输入内容是否发生变化:观察输出模式下且输出内容发生变化则不认为写超时
    449                     if (hasOutputChanged(ctx, first)) {
    450                         return;
    451                     }
    452                     //传递写超时事件
    453                     IdleStateEvent event = newIdleStateEvent(IdleState.WRITER_IDLE, first);
    454                     channelIdle(ctx, event);
    455                 } catch (Throwable t) {
    456                     ctx.fireExceptionCaught(t);
    457                 }
    458             } else {
    459                 // Write occurred before the timeout - set a new timeout with shorter delay.
    460                 writerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
    461             }
    462         }
    463     }
    464 
    465     //读写监测定时任务
    466     private final class AllIdleTimeoutTask extends AbstractIdleTask {
    467 
    468         AllIdleTimeoutTask(ChannelHandlerContext ctx) {
    469             super(ctx);
    470         }
    471 
    472         @Override
    473         protected void run(ChannelHandlerContext ctx) {
    474 
    475             long nextDelay = allIdleTimeNanos;
    476             if (!reading) {
    477                 nextDelay -= ticksInNanos() - Math.max(lastReadTime, lastWriteTime);
    478             }
    479             if (nextDelay <= 0) {
    480                 // Both reader and writer are idle - set a new timeout and
    481                 // notify the callback.
    482                 allIdleTimeout = schedule(ctx, this, allIdleTimeNanos, TimeUnit.NANOSECONDS);
    483 
    484                 boolean first = firstAllIdleEvent;
    485                 firstAllIdleEvent = false;
    486 
    487                 try {
    488                     if (hasOutputChanged(ctx, first)) {
    489                         return;
    490                     }
    491 
    492                     IdleStateEvent event = newIdleStateEvent(IdleState.ALL_IDLE, first);
    493                     channelIdle(ctx, event);
    494                 } catch (Throwable t) {
    495                     ctx.fireExceptionCaught(t);
    496                 }
    497             } else {
    498                 // Either read or write occurred before the timeout - set a new
    499                 // timeout with shorter delay.
    500                 allIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
    501             }
    502         }
    503     }
    504 }

     代码的关键部分都已经给出了注释。

    这里主要关注几个问题,带着这些问题去思考代码设计的目的:

    1.代码中firstXXXIdleEvent的标志位的作用是什么?

    2.ObserveOutput标志位的作用是什么?

    3.reading的标志的作用是什么?

    4.lastReadTime和lastWriteTime会在什么时候被重置?

    首先来回答第一个问题,为什么会有firstXXXIdleEvent的标识。

    这是因为一次读写事件中,可能会产生多次的空闲超时事件。比如当我设置写空闲时间为5秒,而在某些情况下,我整个写过程需要30秒。那么这一次写过程就会产生多个写空闲事件。firstXXXIdleEvent标志位就是用来表明此次空闲事件是否为第一次空闲事件。

    知道了第一个问题后,我们在看ObserveOutput标志的作用。ObserveOutput标志用来解决上述的慢输出的问题。如果设置为true,那么即使写过程中发生了写空闲事件,但是只要hasOutputChanged方法判断此时仍然在向外写(写缓存发生变化),那么就不会为此次超时产生写超时事件。

    那么reading标志的作用是什么?reading的标志是在read方法开始时,被设置为true,在readComplete方法中又被设置为false。也就是reading标志表示正在发生读的过程。

    最后的问题,lastReadTime和lastWriteTime在什么时候被重置?lastReadTime和lastWriteTime会在相应的定时器中被用来和空闲时间作比较,以此来检测在这段空闲时间中,是否发生过完整的读或写过程。因此,它们在handler初始化时被初始化值。lastReadTime会在readComplete时更新值。而lastWriteTime则是在WriterListener中设置(写过程完成后的回掉中)。

  • 相关阅读:
    sitemap.xml生成方法(asp和php)(转)
    浏览器缓存机制(转)
    JavaScript在IE浏览器和Firefox浏览器中的差异总结(转)
    JavaScript的数组及其操作
    Google Maps和GIS开发资源收集
    js 字符串转换成数字(转)
    关于构造函数
    C#类型转化
    .net framework
    C#变量
  • 原文地址:https://www.cnblogs.com/insaneXs/p/9776164.html
Copyright © 2020-2023  润新知