Netty(三):IdleStateHandler源码解析



别说谁变了你拦得住时间么 提交于 2020-10-27 19:25:36

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中设置(写过程完成后的回掉中)。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!