Fork me on GitHub

Netty(六):NioServerSocketChannel源码解析

我们在Netty学习系列五的最后提出了一些问题还没得到回答,今天来通过学习NioServerSocketChannel的源码来帮我们找到之前问题的答案。

先看一下NioServerSocketChannel的继承结构。

 

AttributeMap接口及DefaultAttributeMap主要是提供了体检属性和获取属性的能力,便于我们为Channel绑定额外的属性。

 

AbstractChannel实现了Channel接口,实现了Channel通用的行为和方法,我们在Netty学习系列四中已经介绍过了。

 

AbstractNioChannel抽象类关联了Channel接口与JDK的NIOChannel,也就是让底层的通信交给Nio来实现。

简单介绍下源码:

  1 public abstract class AbstractNioChannel extends AbstractChannel {
  2 
  3     private static final InternalLogger logger =
  4             InternalLoggerFactory.getInstance(AbstractNioChannel.class);
  5 
  6     private static final ClosedChannelException DO_CLOSE_CLOSED_CHANNEL_EXCEPTION = ThrowableUtil.unknownStackTrace(
  7             new ClosedChannelException(), AbstractNioChannel.class, "doClose()");
  8 
  9     //和Java NIO的Channel绑定
 10     private final SelectableChannel ch;
 11     //为SelectableChannel注册的时间
 12     protected final int readInterestOp;
 13     volatile SelectionKey selectionKey;
 14 
 15     boolean readPending;
 16     
 17     private final Runnable clearReadPendingRunnable = new Runnable() {
 18         @Override
 19         public void run() {
 20             clearReadPending0();
 21         }
 22     };
 23 
 24     /**
 25      * The future of the current connection attempt.  If not null, subsequent
 26      * connection attempts will fail.
 27      */
 28     private ChannelPromise connectPromise;
 29     private ScheduledFuture<?> connectTimeoutFuture;
 30     private SocketAddress requestedRemoteAddress;
 31 
 32     //构造函数,参数分别为父Channel,要封装的SelectableChannel和注册的感兴趣的事件
 33     protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
 34         super(parent);
 35         this.ch = ch;
 36         this.readInterestOp = readInterestOp;
 37         try {
 38             //将SelectableChannel设置为非阻塞
 39             ch.configureBlocking(false);
 40         } catch (IOException e) {
 41             try {
 42                 ch.close();
 43             } catch (IOException e2) {
 44                 if (logger.isWarnEnabled()) {
 45                     logger.warn(
 46                             "Failed to close a partially initialized socket.", e2);
 47                 }
 48             }
 49 
 50             throw new ChannelException("Failed to enter non-blocking mode.", e);
 51         }
 52     }
 53 
 54     //通道是否打开
 55     @Override
 56     public boolean isOpen() {
 57         return ch.isOpen();
 58     }
 59 
 60     //返回更具体的Unsafe子类
 61     @Override
 62     public NioUnsafe unsafe() {
 63         return (NioUnsafe) super.unsafe();
 64     }
 65 
 66     //返回内部封装的SelectableChannel
 67     protected SelectableChannel javaChannel() {
 68         return ch;
 69     }
 70 
 71     //返回EventLoop更具体的子类
 72     @Override
 73     public NioEventLoop eventLoop() {
 74         return (NioEventLoop) super.eventLoop();
 75     }
 76 
 77     //返回SelectionKey
 78     protected SelectionKey selectionKey() {
 79         assert selectionKey != null;
 80         return selectionKey;
 81     }
 82 
 83     //已废弃方法
 84     @Deprecated
 85     protected boolean isReadPending() {
 86         return readPending;
 87     }
 88 
 89     //已废弃方法
 90     @Deprecated
 91     protected void setReadPending(final boolean readPending) {
 92         if (isRegistered()) {
 93             EventLoop eventLoop = eventLoop();
 94             if (eventLoop.inEventLoop()) {
 95                 setReadPending0(readPending);
 96             } else {
 97                 eventLoop.execute(new Runnable() {
 98                     @Override
 99                     public void run() {
100                         setReadPending0(readPending);
101                     }
102                 });
103             }
104         } else {
105             // Best effort if we are not registered yet clear readPending.
106             // NB: We only set the boolean field instead of calling clearReadPending0(), because the SelectionKey is
107             // not set yet so it would produce an assertion failure.
108             this.readPending = readPending;
109         }
110     }
111 
112     /**
113      * Set read pending to {@code false}.
114      */
115     protected final void clearReadPending() {
116         if (isRegistered()) {
117             EventLoop eventLoop = eventLoop();
118             if (eventLoop.inEventLoop()) {
119                 clearReadPending0();
120             } else {
121                 eventLoop.execute(clearReadPendingRunnable);
122             }
123         } else {
124             // Best effort if we are not registered yet clear readPending. This happens during channel initialization.
125             // NB: We only set the boolean field instead of calling clearReadPending0(), because the SelectionKey is
126             // not set yet so it would produce an assertion failure.
127             readPending = false;
128         }
129     }
130 
131     private void setReadPending0(boolean readPending) {
132         this.readPending = readPending;
133         if (!readPending) {
134             ((AbstractNioUnsafe) unsafe()).removeReadOp();
135         }
136     }
137 
138     private void clearReadPending0() {
139         readPending = false;
140         ((AbstractNioUnsafe) unsafe()).removeReadOp();
141     }
142 
143     //Unsafe的具体子类,增加了一些和NioChannel相关的特性
144     public interface NioUnsafe extends Unsafe {
145         //返回内部的SelectableChannel
146         SelectableChannel ch();
147 
148         //连接完成
149         void finishConnect();
150 
151         //读方法
152         void read();
153 
154         //强制刷新
155         void forceFlush();
156     }
157 
158     //NioUnsafe的抽象实现
159     protected abstract class AbstractNioUnsafe extends AbstractUnsafe implements NioUnsafe {
160 
161         protected final void removeReadOp() {
162             SelectionKey key = selectionKey();
163             // Check first if the key is still valid as it may be canceled as part of the deregistration
164             // from the EventLoop
165             // See https://github.com/netty/netty/issues/2104
166             if (!key.isValid()) {
167                 return;
168             }
169             int interestOps = key.interestOps();
170             if ((interestOps & readInterestOp) != 0) {
171                 // only remove readInterestOp if needed
172                 key.interestOps(interestOps & ~readInterestOp);
173             }
174         }
175 
176         //返回内部封装的Channel
177         @Override
178         public final SelectableChannel ch() {
179             return javaChannel();
180         }
181 
182         //connect方法,实际在使用时NioServerSocket是不支持connect的,但是NioSocket会支持
183         @Override
184         public final void connect(
185                 final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
186             if (!promise.setUncancellable() || !ensureOpen(promise)) {
187                 return;
188             }
189 
190             try {
191                 if (connectPromise != null) {
192                     // Already a connect in process.
193                     throw new ConnectionPendingException();
194                 }
195 
196                 boolean wasActive = isActive();
197                 //调用具体子类的doConnect方法
198                 if (doConnect(remoteAddress, localAddress)) {
199                     //连接成功设置fulfillConnectPromise
200                     fulfillConnectPromise(promise, wasActive);
201                 } else {
202                     //连接未成功
203                     connectPromise = promise;
204                     requestedRemoteAddress = remoteAddress;
205 
206                     //根据配置的超时时间,设置超时任务,一旦到达超时时间则抛出连接失败的异常
207                     int connectTimeoutMillis = config().getConnectTimeoutMillis();
208                     if (connectTimeoutMillis > 0) {
209                         connectTimeoutFuture = eventLoop().schedule(new Runnable() {
210                             @Override
211                             public void run() {
212                                 ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise;
213                                 ConnectTimeoutException cause =
214                                         new ConnectTimeoutException("connection timed out: " + remoteAddress);
215                                 if (connectPromise != null && connectPromise.tryFailure(cause)) {
216                                     close(voidPromise());
217                                 }
218                             }
219                         }, connectTimeoutMillis, TimeUnit.MILLISECONDS);
220                     }
221 
222                     //添加监听器,如果期间操作成功了,则取消掉超超时任务
223                     promise.addListener(new ChannelFutureListener() {
224                         @Override
225                         public void operationComplete(ChannelFuture future) throws Exception {
226                             if (future.isCancelled()) {
227                                 if (connectTimeoutFuture != null) {
228                                     connectTimeoutFuture.cancel(false);
229                                 }
230                                 connectPromise = null;
231                                 close(voidPromise());
232                             }
233                         }
234                     });
235                 }
236             } catch (Throwable t) {
237                 //运行出现异常,则设置Promise为失败
238                 promise.tryFailure(annotateConnectException(t, remoteAddress));
239                 closeIfClosed();
240             }
241         }
242 
243         private void fulfillConnectPromise(ChannelPromise promise, boolean wasActive) {
244             if (promise == null) {
245                 // Closed via cancellation and the promise has been notified already.
246                 return;
247             }
248 
249             // Get the state as trySuccess() may trigger an ChannelFutureListener that will close the Channel.
250             // We still need to ensure we call fireChannelActive() in this case.
251             boolean active = isActive();
252 
253             // trySuccess() will return false if a user cancelled the connection attempt.
254             boolean promiseSet = promise.trySuccess();
255 
256 
257             //active状态发生改变,现在已经连接成功
258             if (!wasActive && active) {
259                 //pipeline产生Active事件在通道中流传
260                 pipeline().fireChannelActive();
261             }
262 
263             // If a user cancelled the connection attempt, close the channel, which is followed by channelInactive().
264             if (!promiseSet) {
265                 close(voidPromise());
266             }
267         }
268 
269         private void fulfillConnectPromise(ChannelPromise promise, Throwable cause) {
270             if (promise == null) {
271                 // Closed via cancellation and the promise has been notified already.
272                 return;
273             }
274 
275             // Use tryFailure() instead of setFailure() to avoid the race against cancel().
276             promise.tryFailure(cause);
277             closeIfClosed();
278         }
279 
280         //连接完成,该方法会在连接成功后,由EventLoop调用
281         @Override
282         public final void finishConnect() {
283 
284             assert eventLoop().inEventLoop();
285 
286             try {
287                 boolean wasActive = isActive();
288                 doFinishConnect();
289                 fulfillConnectPromise(connectPromise, wasActive);
290             } catch (Throwable t) {
291                 fulfillConnectPromise(connectPromise, annotateConnectException(t, requestedRemoteAddress));
292             } finally {
293                 // Check for null as the connectTimeoutFuture is only created if a connectTimeoutMillis > 0 is used
294                 // See https://github.com/netty/netty/issues/1770
295                 if (connectTimeoutFuture != null) {
296                     connectTimeoutFuture.cancel(false);
297                 }
298                 connectPromise = null;
299             }
300         }
301 
302         @Override
303         protected final void flush0() {
304             // Flush immediately only when there's no pending flush.
305             // If there's a pending flush operation, event loop will call forceFlush() later,
306             // and thus there's no need to call it now.
307             if (!isFlushPending()) {
308                 super.flush0();
309             }
310         }
311 
312         @Override
313         public final void forceFlush() {
314             // directly call super.flush0() to force a flush now
315             super.flush0();
316         }
317 
318         private boolean isFlushPending() {
319             SelectionKey selectionKey = selectionKey();
320             return selectionKey.isValid() && (selectionKey.interestOps() & SelectionKey.OP_WRITE) != 0;
321         }
322     }
323 
324     //判断EventLoop和Channel是否匹配
325     @Override
326     protected boolean isCompatible(EventLoop loop) {
327         return loop instanceof NioEventLoop;
328     }
329 
330     //注册
331     @Override
332     protected void doRegister() throws Exception {
333         boolean selected = false;
334         for (;;) {
335             try {
336                 //让内部的javaChannel先注册的interestOps为0
337                 selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
338                 return;
339             } catch (CancelledKeyException e) {
340                 if (!selected) {
341                     // Force the Selector to select now as the "canceled" SelectionKey may still be
342                     // cached and not removed because no Select.select(..) operation was called yet.
343                     eventLoop().selectNow();
344                     selected = true;
345                 } else {
346                     // We forced a select operation on the selector before but the SelectionKey is still cached
347                     // for whatever reason. JDK bug ?
348                     throw e;
349                 }
350             }
351         }
352     }
353 
354     @Override
355     protected void doDeregister() throws Exception {
356         eventLoop().cancel(selectionKey());
357     }
358 
359     //doBeginRead由read方法调用
360     @Override
361     protected void doBeginRead() throws Exception {
362         final SelectionKey selectionKey = this.selectionKey;
363         if (!selectionKey.isValid()) {
364             return;
365         }
366 
367         readPending = true;
368         //重新注册感兴趣的事件
369         final int interestOps = selectionKey.interestOps();
370         if ((interestOps & readInterestOp) == 0) {
371             selectionKey.interestOps(interestOps | readInterestOp);
372         }
373     }
374 
375     /**
376      * Connect to the remote peer
377      */
378     protected abstract boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception;
379 
380     /**
381      * Finish the connect
382      */
383     protected abstract void doFinishConnect() throws Exception;
384 
385     //分配直接内存
386     protected final ByteBuf newDirectBuffer(ByteBuf buf) {
387         final int readableBytes = buf.readableBytes();
388         if (readableBytes == 0) {
389             ReferenceCountUtil.safeRelease(buf);
390             return Unpooled.EMPTY_BUFFER;
391         }
392 
393         final ByteBufAllocator alloc = alloc();
394         if (alloc.isDirectBufferPooled()) {
395             ByteBuf directBuf = alloc.directBuffer(readableBytes);
396             directBuf.writeBytes(buf, buf.readerIndex(), readableBytes);
397             ReferenceCountUtil.safeRelease(buf);
398             return directBuf;
399         }
400 
401         final ByteBuf directBuf = ByteBufUtil.threadLocalDirectBuffer();
402         if (directBuf != null) {
403             directBuf.writeBytes(buf, buf.readerIndex(), readableBytes);
404             ReferenceCountUtil.safeRelease(buf);
405             return directBuf;
406         }
407 
408         // Allocating and deallocating an unpooled direct buffer is very expensive; give up.
409         return buf;
410     }
411 
412     //分配直接内存
413     protected final ByteBuf newDirectBuffer(ReferenceCounted holder, ByteBuf buf) {
414         final int readableBytes = buf.readableBytes();
415         if (readableBytes == 0) {
416             ReferenceCountUtil.safeRelease(holder);
417             return Unpooled.EMPTY_BUFFER;
418         }
419 
420         final ByteBufAllocator alloc = alloc();
421         if (alloc.isDirectBufferPooled()) {
422             ByteBuf directBuf = alloc.directBuffer(readableBytes);
423             directBuf.writeBytes(buf, buf.readerIndex(), readableBytes);
424             ReferenceCountUtil.safeRelease(holder);
425             return directBuf;
426         }
427 
428         final ByteBuf directBuf = ByteBufUtil.threadLocalDirectBuffer();
429         if (directBuf != null) {
430             directBuf.writeBytes(buf, buf.readerIndex(), readableBytes);
431             ReferenceCountUtil.safeRelease(holder);
432             return directBuf;
433         }
434 
435         // Allocating and deallocating an unpooled direct buffer is very expensive; give up.
436         if (holder != buf) {
437             // Ensure to call holder.release() to give the holder a chance to release other resources than its content.
438             buf.retain();
439             ReferenceCountUtil.safeRelease(holder);
440         }
441 
442         return buf;
443     }
444 
445     //关闭方法
446     @Override
447     protected void doClose() throws Exception {
448         ChannelPromise promise = connectPromise;
449         if (promise != null) {
450             // Use tryFailure() instead of setFailure() to avoid the race against cancel().
451             promise.tryFailure(DO_CLOSE_CLOSED_CHANNEL_EXCEPTION);
452             connectPromise = null;
453         }
454 
455         ScheduledFuture<?> future = connectTimeoutFuture;
456         if (future != null) {
457             future.cancel(false);
458             connectTimeoutFuture = null;
459         }
460     }
461 }
View Code

 

AbstractNioChannel又有两个子类,分别是AbstractNioMessageChannel和AbstractNioByteChannel。两者的区别是前者的通道中封装处理的是Object,而后者的通道中封装处理的是ByteBuf(或FileRegion)。

对于NioServerSocketChannel而言,需要处理的是NioSocketChannel。因此它集成了AbstractNioMessageChannel。

AbstractNioMessageChannel源码:

  1 public abstract class AbstractNioMessageChannel extends AbstractNioChannel {
  2     boolean inputShutdown;
  3 
  4     //构造函数
  5     protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
  6         //设置父Channel, 内部封装的JDKchannel和注册interestOp
  7         super(parent, ch, readInterestOp);
  8     }
  9 
 10     //返回Unsafe对象
 11     @Override
 12     protected AbstractNioUnsafe newUnsafe() {
 13         return new NioMessageUnsafe();
 14     }
 15 
 16     //
 17     @Override
 18     protected void doBeginRead() throws Exception {
 19         if (inputShutdown) {
 20             return;
 21         }
 22         super.doBeginRead();
 23     }
 24 
 25     //AbstractNioUnsafe对象的
 26     private final class NioMessageUnsafe extends AbstractNioUnsafe {
 27 
 28         private final List<Object> readBuf = new ArrayList<Object>();
 29 
 30         @Override
 31         public void read() {
 32             assert eventLoop().inEventLoop();
 33             final ChannelConfig config = config();
 34             final ChannelPipeline pipeline = pipeline();
 35             final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
 36             allocHandle.reset(config);
 37 
 38             boolean closed = false;
 39             Throwable exception = null;
 40 
 41             
 42             try {
 43                 try {
 44                     //开始读操作,主要是调用子类的doReadMessages实现,从SelectableChannel中读取数据,并封装到readBuf
 45                     do {
 46                         int localRead = doReadMessages(readBuf);
 47                         if (localRead == 0) {
 48                             break;
 49                         }
 50                         if (localRead < 0) {
 51                             closed = true;
 52                             break;
 53                         }
 54 
 55                         allocHandle.incMessagesRead(localRead);
 56                     } while (allocHandle.continueReading());
 57                 } catch (Throwable t) {
 58                     exception = t;
 59                 }
 60 
 61                 //将读到的readBuf通过pipline,在通道中流通,便于被通道中的Handler处理
 62                 int size = readBuf.size();
 63                 for (int i = 0; i < size; i ++) {
 64                     readPending = false;
 65                     pipeline.fireChannelRead(readBuf.get(i));
 66                 }
 67                 //清空
 68                 readBuf.clear();
 69                 //读完成,产生readCompleate事件
 70                 allocHandle.readComplete();
 71                 pipeline.fireChannelReadComplete();
 72 
 73                 //如果有异常,则产生异常事件
 74                 if (exception != null) {
 75                     closed = closeOnReadError(exception);
 76 
 77                     pipeline.fireExceptionCaught(exception);
 78                 }
 79 
 80                 //如果被关闭,则调用关闭
 81                 if (closed) {
 82                     inputShutdown = true;
 83                     if (isOpen()) {
 84                         close(voidPromise());
 85                     }
 86                 }
 87             } finally {
 88                 // Check if there is a readPending which was not processed yet.
 89                 // This could be for two reasons:
 90                 // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
 91                 // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
 92                 //
 93                 // See https://github.com/netty/netty/issues/2254
 94                 if (!readPending && !config.isAutoRead()) {
 95                     removeReadOp();
 96                 }
 97             }
 98         }
 99     }
100 
101 
102 
103     //写操作,NioServerSocketChannel不支持写
104     @Override
105     protected void doWrite(ChannelOutboundBuffer in) throws Exception {
106         final SelectionKey key = selectionKey();
107         final int interestOps = key.interestOps();
108 
109         for (;;) {
110             Object msg = in.current();
111             if (msg == null) {
112                 //如果注册了写事件,则移除写事件
113                 if ((interestOps & SelectionKey.OP_WRITE) != 0) {
114                     key.interestOps(interestOps & ~SelectionKey.OP_WRITE);
115                 }
116                 break;
117             }
118             try {
119                 boolean done = false;
120                 for (int i = config().getWriteSpinCount() - 1; i >= 0; i--) {
121                     //具体的写操作交给子类实现(NioServerSocketChannel不支持写操作)
122                     if (doWriteMessage(msg, in)) {
123                         done = true;
124                         break;
125                     }
126                 }
127 
128                 if (done) {
129                     in.remove();
130                 } else {
131                     // Did not write all messages.
132                     if ((interestOps & SelectionKey.OP_WRITE) == 0) {
133                         key.interestOps(interestOps | SelectionKey.OP_WRITE);
134                     }
135                     break;
136                 }
137             } catch (Exception e) {
138                 if (continueOnWriteError()) {
139                     in.remove(e);
140                 } else {
141                     throw e;
142                 }
143             }
144         }
145     }
146 
147     /**
148      * Returns {@code true} if we should continue the write loop on a write error.
149      */
150     protected boolean continueOnWriteError() {
151         return false;
152     }
153 
154 
155     protected boolean closeOnReadError(Throwable cause) {
156         if (!isActive()) {
157             // If the channel is not active anymore for whatever reason we should not try to continue reading.
158             return true;
159         }
160         if (cause instanceof PortUnreachableException) {
161             return false;
162         }
163         if (cause instanceof IOException) {
164             // ServerChannel should not be closed even on IOException because it can often continue
165             // accepting incoming connections. (e.g. too many open files)
166             return !(this instanceof ServerChannel);
167         }
168         return true;
169     }
170 
171     //读和写的具体操作交给子类去实现
172     protected abstract int doReadMessages(List<Object> buf) throws Exception;
173 
174     protected abstract boolean doWriteMessage(Object msg, ChannelOutboundBuffer in) throws Exception;
175 }
View Code

 

最后来看NioServerSocketChannel源码:

  1 public class NioServerSocketChannel extends AbstractNioMessageChannel
  2                              implements io.netty.channel.socket.ServerSocketChannel {
  3 
  4     private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
  5     private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
  6 
  7     private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioServerSocketChannel.class);
  8 
  9     //产生NIOServerSocketChannel的方法
 10     private static ServerSocketChannel newSocket(SelectorProvider provider) {
 11         try {
 12             /**
 13              *  Use the {@link SelectorProvider} to open {@link SocketChannel} and so remove condition in
 14              *  {@link SelectorProvider#provider()} which is called by each ServerSocketChannel.open() otherwise.
 15              *
 16              *  See <a href="https://github.com/netty/netty/issues/2308">#2308</a>.
 17              */
 18             return provider.openServerSocketChannel();
 19         } catch (IOException e) {
 20             throw new ChannelException(
 21                     "Failed to open a server socket.", e);
 22         }
 23     }
 24 
 25     private final ServerSocketChannelConfig config;
 26 
 27     //默认构造函数, ReflectivaChannelFactory利用反射创建Channel时,即是调用了这个方法
 28     public NioServerSocketChannel() {
 29         this(newSocket(DEFAULT_SELECTOR_PROVIDER));
 30     }
 31 
 32     /**
 33      * Create a new instance using the given {@link SelectorProvider}.
 34      */
 35     public NioServerSocketChannel(SelectorProvider provider) {
 36         this(newSocket(provider));
 37     }
 38 
 39     //将NIO中的ServerSocketChannel封装成Netty的NioServerSocketChannel
 40     public NioServerSocketChannel(ServerSocketChannel channel) {
 41         //调用父类的构造函数,注意设置了interestOps为OP_ACCEPT
 42         super(null, channel, SelectionKey.OP_ACCEPT);
 43         //创建配置
 44         config = new NioServerSocketChannelConfig(this, javaChannel().socket());
 45     }
 46 
 47     //返回以太网地址
 48     @Override
 49     public InetSocketAddress localAddress() {
 50         return (InetSocketAddress) super.localAddress();
 51     }
 52 
 53     //返回元数据信息
 54     @Override
 55     public ChannelMetadata metadata() {
 56         return METADATA;
 57     }
 58 
 59     //返回配置
 60     @Override
 61     public ServerSocketChannelConfig config() {
 62         return config;
 63     }
 64 
 65     //Channel是否活跃
 66     @Override
 67     public boolean isActive() {
 68         //通过socket的bound状态来确定是否为active
 69         return javaChannel().socket().isBound();
 70     }
 71 
 72     //返回远端地址,ServerSocketChannel没有对应的远端地址
 73     @Override
 74     public InetSocketAddress remoteAddress() {
 75         return null;
 76     }
 77 
 78     //内部封装的JDK自带的Channel
 79     @Override
 80     protected ServerSocketChannel javaChannel() {
 81         return (ServerSocketChannel) super.javaChannel();
 82     }
 83 
 84     @Override
 85     protected SocketAddress localAddress0() {
 86         return SocketUtils.localSocketAddress(javaChannel().socket());
 87     }
 88 
 89     //通过调用内部封装的JDK中的NIO channel来绑定地址
 90     @Override
 91     protected void doBind(SocketAddress localAddress) throws Exception {
 92         if (PlatformDependent.javaVersion() >= 7) {
 93             javaChannel().bind(localAddress, config.getBacklog());
 94         } else {
 95             javaChannel().socket().bind(localAddress, config.getBacklog());
 96         }
 97     }
 98 
 99     //关闭通道
100     @Override
101     protected void doClose() throws Exception {
102         javaChannel().close();
103     }
104 
105     //读消息
106     @Override
107     protected int doReadMessages(List<Object> buf) throws Exception {
108         //其实就是调用ServerSocketChannel的accept方法监听accept事件,返回SocketChannel
109         SocketChannel ch = SocketUtils.accept(javaChannel());
110 
111         try {
112             //将JDK NIO中的channel封装成Netty的NioSocketChannel对象,添加进buf中,使其在Pipeline中传递
113             if (ch != null) {
114                 buf.add(new NioSocketChannel(this, ch));
115                 return 1;//返回数量
116             }
117         } catch (Throwable t) {
118             logger.warn("Failed to create a new channel from an accepted socket.", t);
119 
120             try {
121                 ch.close();
122             } catch (Throwable t2) {
123                 logger.warn("Failed to close a socket.", t2);
124             }
125         }
126 
127         return 0;
128     }
129 
130     //NIOServerSocketChannel不支持的部分操作 返回null 或者 UnsuppotedOperationException异常
131     @Override
132     protected boolean doConnect(
133             SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
134         throw new UnsupportedOperationException();
135     }
136 
137     @Override
138     protected void doFinishConnect() throws Exception {
139         throw new UnsupportedOperationException();
140     }
141 
142     @Override
143     protected SocketAddress remoteAddress0() {
144         return null;
145     }
146 
147     @Override
148     protected void doDisconnect() throws Exception {
149         throw new UnsupportedOperationException();
150     }
151 
152     @Override
153     protected boolean doWriteMessage(Object msg, ChannelOutboundBuffer in) throws Exception {
154         throw new UnsupportedOperationException();
155     }
156 
157     @Override
158     protected final Object filterOutboundMessage(Object msg) throws Exception {
159         throw new UnsupportedOperationException();
160     }
161 
162     /********************************************************************/
163 
164 
165     private final class NioServerSocketChannelConfig extends DefaultServerSocketChannelConfig {
166         private NioServerSocketChannelConfig(NioServerSocketChannel channel, ServerSocket javaSocket) {
167             super(channel, javaSocket);
168         }
169 
170         @Override
171         protected void autoReadCleared() {
172             clearReadPending();
173         }
174     }
175 
176     // Override just to to be able to call directly via unit tests.
177     @Override
178     protected boolean closeOnReadError(Throwable cause) {
179         return super.closeOnReadError(cause);
180     }
181 }
View Code

 

分析完源码,再来看看上一篇文章中提出的问题:

为什么一开始register中注册的interestOps值为0,而非OP_ACCEPT?又是何时会注册OP_ACCEPT呢?

首先我们通过分析NioServerSocketChannel的源码可以看到:

channelFactory会通过发射创建NioServerSocketChannel对象。而发射调用的构造函数中设置了readInterestOps的值为OP_ACCEPT。而在AbstractNioChannel的doBeginRead方法中又会将readInterestOps注册到channel。

根据方法名我们可以猜测在开始读之前,selectableChannel的interestOps会从0被改为OP_ACCEPT。

为了证实这点,我们需要弄清楚开始时register interestOps为0的时机和调用doBeginRead的时机。

首先注册interestOps为0是在AbstractNioChannel的doRegister方法中。我们知道这个方法发生在channel的注册阶段。

再看doBeginRead的函数调用:

之前已经介绍过了注册或者绑定成功后,会调用pipeline.fireChannelActive事件。此时的DefaultChannelPipeline除了传递channelActive事件之外,还会调用readIfAutoRead()。

这个方法会根据Config配置的AutoRead属性来决定是否调用read方法。

而这个属性默认是自动读的。于是就可以调用read方法,并最终为channel注册OP_ACCEPT事件。

posted @ 2018-11-21 19:42  insaneXs  阅读(661)  评论(0编辑  收藏  举报