一、NioSocketChannel的初始化
- 从NioEventLoop开始说起
我们在服务端启动后,boss线程组会启动一个NioEventLoop线程,它会在run方法中无限循环接收感兴趣的事件//1. NioEventLoop //新连接进来会触发ACCEPT事件 @Override protected void run() { for (;;) { try { switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) { case SelectStrategy.CONTINUE: continue; case SelectStrategy.SELECT: select(wakenUp.getAndSet(false)); if (wakenUp.get()) { selector.wakeup(); } // fall through default: } cancelledKeys = 0; needsToSelectAgain = false; final int ioRatio = this.ioRatio; if (ioRatio == 100) { try { processSelectedKeys(); } finally { // Ensure we always run tasks. runAllTasks(); } } else { final long ioStartTime = System.nanoTime(); try { //处理selectkey //1 - (1) processSelectedKeys(); } finally { // Ensure we always run tasks. final long ioTime = System.nanoTime() - ioStartTime; runAllTasks(ioTime * (100 - ioRatio) / ioRatio); } } } catch (Throwable t) { handleLoopException(t); } // Always handle shutdown even if the loop processing threw an exception. try { if (isShuttingDown()) { closeAll(); if (confirmShutdown()) { return; } } } catch (Throwable t) { handleLoopException(t); } } } //1 - (1) private void processSelectedKeys() { if (selectedKeys != null) { //1 - (2) processSelectedKeysOptimized(); } else { processSelectedKeysPlain(selector.selectedKeys()); } } //1 - (3) private void processSelectedKeysOptimized() { for (int i = 0; i < selectedKeys.size; ++i) { final SelectionKey k = selectedKeys.keys[i]; // null out entry in the array to allow to have it GC'ed once the Channel close // See https://github.com/netty/netty/issues/2363 selectedKeys.keys[i] = null; //拿到selector时候netty设置然后jdk保存的NioServerSocketChannel final Object a = k.attachment(); if (a instanceof AbstractNioChannel) { //1 - (4) processSelectedKey(k, (AbstractNioChannel) a); } else { @SuppressWarnings("unchecked") NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a; processSelectedKey(k, task); } if (needsToSelectAgain) { // null out entries in the array to allow to have it GC'ed once the Channel close // See https://github.com/netty/netty/issues/2363 selectedKeys.reset(i + 1); selectAgain(); i = -1; } } } //1 - (4) 这里就类似java的Nio处理不同的感兴趣事件 private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) { final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe(); if (!k.isValid()) { final EventLoop eventLoop; try { eventLoop = ch.eventLoop(); } catch (Throwable ignored) { // If the channel implementation throws an exception because there is no event loop, we ignore this // because we are only trying to determine if ch is registered to this event loop and thus has authority // to close ch. return; } // Only close ch if ch is still registered to this EventLoop. ch could have deregistered from the event loop // and thus the SelectionKey could be cancelled as part of the deregistration process, but the channel is // still healthy and should not be closed. // See https://github.com/netty/netty/issues/5125 if (eventLoop != this || eventLoop == null) { return; } // close the channel if the key is not valid anymore unsafe.close(unsafe.voidPromise()); return; } try { int readyOps = k.readyOps(); // We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise // the NIO JDK channel implementation may throw a NotYetConnectedException. if ((readyOps & SelectionKey.OP_CONNECT) != 0) { // remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking // See https://github.com/netty/netty/issues/924 int ops = k.interestOps(); ops &= ~SelectionKey.OP_CONNECT; k.interestOps(ops); unsafe.finishConnect(); } // Process OP_WRITE first as we may be able to write some queued buffers and so free memory. if ((readyOps & SelectionKey.OP_WRITE) != 0) { // Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write ch.unsafe().forceFlush(); } // Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead // to a spin loop if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) { //会进入到NioMessageUnsafe的read方法 //1 - (5) unsafe.read(); } } catch (CancelledKeyException ignored) { unsafe.close(unsafe.voidPromise()); } } //1 - (5) NioMessageUnsafe @Override public void read() { //是否在当前EventLoop线程 assert eventLoop().inEventLoop(); //NioServerSocketChannel的config final ChannelConfig config = config(); //NioServerSocketChannel的通道 final ChannelPipeline pipeline = pipeline(); //分配一个接收缓冲区,二分算法获取一个不会浪费空间又又足够大小缓冲区 final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle(); //重置计数器 allocHandle.reset(config); boolean closed = false; Throwable exception = null; try { try { do { //1 - (6) int localRead = doReadMessages(readBuf); if (localRead == 0) { break; } if (localRead < 0) { closed = true; break; } //总消息数加一 allocHandle.incMessagesRead(localRead); //是否继续读消息 //1 - (11) } while (allocHandle.continueReading()); } catch (Throwable t) { exception = t; } int size = readBuf.size(); for (int i = 0; i < size; i ++) { readPending = false; //关键地方来了,NioSocketChannel的注册和绑定到selector上 //调用NioServerSocketChannel的pipeline中ChannelHandler的read //1 - (12) pipeline.fireChannelRead(readBuf.get(i)); } readBuf.clear(); allocHandle.readComplete(); //read完成事件 pipeline.fireChannelReadComplete(); if (exception != null) { closed = closeOnReadError(exception); pipeline.fireExceptionCaught(exception); } if (closed) { inputShutdown = true; if (isOpen()) { close(voidPromise()); } } } finally { // Check if there is a readPending which was not processed yet. // This could be for two reasons: // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method // // See https://github.com/netty/netty/issues/2254 if (!readPending && !config.isAutoRead()) { removeReadOp(); } } } //1 - (6) NioServerSocketChannel @Override protected int doReadMessages(List<Object> buf) throws Exception { //获取Java的SocketChannel SocketChannel ch = SocketUtils.accept(javaChannel()); try { if (ch != null) { //包装成netty的的NioSocketChannel并加进NioMessageUnsafe的readBuf集合中 //1 - (7) buf.add(new NioSocketChannel(this, ch)); return 1; } } catch (Throwable t) { logger.warn("Failed to create a new channel from an accepted socket.", t); try { ch.close(); } catch (Throwable t2) { logger.warn("Failed to close a socket.", t2); } } return 0; } //1 - (7) NioSocketChannel --- 初始化 public NioSocketChannel(Channel parent, SocketChannel socket) { //1 - (8) super(parent, socket); //创建并保存NioSocketChannelConfig config = new NioSocketChannelConfig(this, socket.socket()); } //1 - (8) AbstractNioByteChannel protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) { //1 - (9) super(parent, ch, SelectionKey.OP_READ); } //1 - (9) AbstractNioChannel protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) { //1 - (10) super(parent); this.ch = ch; //保存感兴趣的读事件 this.readInterestOp = readInterestOp; try { //jdk的非阻塞获取连接 ch.configureBlocking(false); } catch (IOException e) { try { ch.close(); } catch (IOException e2) { if (logger.isWarnEnabled()) { logger.warn( "Failed to close a partially initialized socket.", e2); } } throw new ChannelException("Failed to enter non-blocking mode.", e); } } //1 - (10) AbstractChannel protected AbstractChannel(Channel parent) { //保存NioServerSocketChannel this.parent = parent; //设置一个id id = newId(); //创建并保存NioSocketChannelUnsafe unsafe = newUnsafe(); //创建并保存DefaultChannelPipeline pipeline = newChannelPipeline(); } //1 - (11) @Override public boolean continueReading() { return continueReading(defaultMaybeMoreSupplier); } @Override public boolean continueReading(UncheckedBooleanSupplier maybeMoreDataSupplier) { //config.isAutoRead() true //respectMaybeMoreData true //maybeMoreDataSupplier.get() true //totalMessages < maxMessagePerRead true //totalBytesRead > 0 false return config.isAutoRead() && (!respectMaybeMoreData || maybeMoreDataSupplier.get()) && totalMessages < maxMessagePerRead && totalBytesRead > 0; } //1 - (12) DefaultChannelPipeline @Override public final ChannelPipeline fireChannelRead(Object msg) { //1 - (13) AbstractChannelHandlerContext.invokeChannelRead(head, msg); return this; } //1 - (13) AbstractChannelHandlerContext static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) { //m=NioSocketChannel final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next); EventExecutor executor = next.executor(); if (executor.inEventLoop()) { //1 - (14) next.invokeChannelRead(m); } else { executor.execute(new Runnable() { @Override public void run() { next.invokeChannelRead(m); } }); } } //1 - (14) AbstractChannelHandlerContext private void invokeChannelRead(Object msg) { if (invokeHandler()) { try { //head节点开始 → ServerBootstrapAcceptor //1 - (15) ((ChannelInboundHandler) handler()).channelRead(this, msg); } catch (Throwable t) { notifyHandlerException(t); } } else { fireChannelRead(msg); } } //1 - (15) @Override @SuppressWarnings("unchecked") public void channelRead(ChannelHandlerContext ctx, Object msg) { //child = NioSocketChannel final Channel child = (Channel) msg; //NioSocketChannel的pipeline中把设置的ChannelHandler添加进去 child.pipeline().addLast(childHandler); //设置TCP参数 setChannelOptions(child, childOptions, logger); //设置属性 for (Entry<AttributeKey<?>, Object> e: childAttrs) { child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue()); } try { //这里就类似Server端NioServerSocketChannel的初始化 //从worker线程组拿一个NioEventLoop 并将NioSocketChannel注册到NioEventLoop 上 childGroup.register(child).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { forceClose(child, future.cause()); } } }); } catch (Throwable t) { forceClose(child, t); } }