Netty(三):IdleStateHandler源碼解析

IdleStateHandler是Netty爲咱們提供的檢測鏈接有效性的處理器,一共有讀空閒,寫空閒,讀/寫空閒三種監測機制。java

將其添加到咱們的ChannelPipline中,即可以用來檢測空閒。express

 

先經過一段代碼來學習下IdleStateHandler的用法:apache

ConnectStateHandler:(負責監測通道的各類狀態並處理空閒事件IdleStateEvent)bootstrap

 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 }

 服務器代碼:promise

 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的狀態變化:app

1.鏈接創建時會從register -> active,less

2.當讀空閒時,咱們產生了一個空閒事件,當ConnectStateHandler捕獲這個事件後,會主動斷開鏈接。 socket

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中設置(寫過程完成後的回掉中)。

相關文章
相關標籤/搜索