• 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事件。

  • 相关阅读:
    第二期冲刺会议3
    第二期站立会议2
    意见汇总及改进方案
    第二期站立会议1
    第一期站立会议7
    第一期站立会议6
    第一期站立会议5
    第一期站立会议4
    第一期站立会议3
    第一期站立会议2
  • 原文地址:https://www.cnblogs.com/insaneXs/p/9993014.html
Copyright © 2020-2023  润新知