netty accept

首先一段标准的netty代码

val bossGroup = NioEventLoopGroup()
val workerGroup = NioEventLoopGroup()
try {
    val bootstrap = ServerBootstrap()
    bootstrap.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel::class.java)
            .option(ChannelOption.SO_BACKLOG, 1024)
            .childHandler(object : ChannelInitializer<SocketChannel>(){
                override fun initChannel(ch: SocketChannel) {
                    ch.pipeline().addLast("heartbeat", HeartBeatHandler())

                }
            })

    val future = bootstrap.bind("localhost", port)
    println("服务启动 port is $port")

    //等待链路关闭
    future.channel().closeFuture().sync()
}finally {
   
    bossGroup.shutdownGracefully()
    workerGroup.shutdownGracefully()
}

bind方法会初始化NioServerSocketChannel,并向channel关联的pipeline中添加ChannelInitializer,有客户端连接时初始化,

 p.addLast(new ChannelInitializer<Channel>() {
 @Override
 public void initChannel(final Channel ch) throws Exception {
     final ChannelPipeline pipeline = ch.pipeline();
     ChannelHandler handler = config.handler();
     if (handler != null) {
         pipeline.addLast(handler);
     }

     ch.eventLoop().execute(new Runnable() {
         @Override
         public void run() {
             pipeline.addLast(new ServerBootstrapAcceptor(
                     ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
         }
     });
 }
});

然后从bossGroup中调用next取一个EventLoop注册到channel

ChannelFuture regFuture = config().group().register(channel);

然后调用register方法

@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    if (eventLoop == null) {
        throw new NullPointerException("eventLoop");
    }
    if (isRegistered()) {
        promise.setFailure(new IllegalStateException("registered to an event loop already"));
        return;
    }
    if (!isCompatible(eventLoop)) {
        promise.setFailure(
                new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
        return;
    }

    AbstractChannel.this.eventLoop = eventLoop;

    if (eventLoop.inEventLoop()) { //这里为false
        register0(promise);
    } else {
        try {
        	//会走这里,这里向eventLoop提交了一个任务,同时由于第一次向eventLoop中提交任务所以启动eventLoop关联的线程
            eventLoop.execute(new Runnable() { 
                @Override
                public void run() {
                    register0(promise);   //在关联的eventLoop线程中注册
                    //register0中的主要代码  selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);  注册到select,interestOps为0表示什么都不关注,同时attachment为AbstractNioChannel
                }
            });
        } catch (Throwable t) {
            logger.warn(
                    "Force-closing a channel whose registration task was not accepted by an event loop: {}",
                    AbstractChannel.this, t);
            closeForcibly();
            closeFuture.setClosed();
            safeSetFailure(promise, t);
        }
    }
}

提交任务,启动线程

 public void execute(Runnable task) {
     if (task == null) {
         throw new NullPointerException("task");
     }

     boolean inEventLoop = inEventLoop();
     addTask(task);
     if (!inEventLoop) { //inEventLoop = false
         startThread();
         if (isShutdown() && removeTask(task)) {
             reject();
         }
     }

     if (!addTaskWakesUp && wakesUpForTask(task)) {
         wakeup(inEventLoop);
     }
 }

 //启动线程
private void doStartThread() {
    assert thread == null;
    executor.execute(new Runnable() {
        @Override
        public void run() {
            thread = Thread.currentThread();
            if (interrupted) {
                thread.interrupt();
            }

            boolean success = false;
            updateLastExecutionTime();
            try {
            	//执行run方法
                SingleThreadEventExecutor.this.run();
                success = true;
            } catch (Throwable t) {
                logger.warn("Unexpected exception from an event executor: ", t);
            } finally {
                for (;;) {
                    int oldState = state;
                    if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
                            SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
                        break;
                    }
                }

                // Check if confirmShutdown() was called at the end of the loop.
                if (success && gracefulShutdownStartTime == 0) {
                    if (logger.isErrorEnabled()) {
                        logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
                                SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
                                "be called before run() implementation terminates.");
                    }
                }

                try {
                    // Run all remaining tasks and shutdown hooks.
                    for (;;) {
                        if (confirmShutdown()) {
                            break;
                        }
                    }
                } finally {
                    try {
                        cleanup();
                    } finally {
                        STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
                        threadLock.release();
                        if (!taskQueue.isEmpty()) {
                            if (logger.isWarnEnabled()) {
                                logger.warn("An event executor terminated with " +
                                        "non-empty task queue (" + taskQueue.size() + ')');
                            }
                        }

                        terminationFuture.setSuccess(null);
                    }
                }
            }
        }
    });
}

run方法中

protected void run() {
    for (;;) {
        try {
        	//如果有任务直接调用selectNow()
            switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
                case SelectStrategy.CONTINUE:
                    continue;

                case SelectStrategy.BUSY_WAIT:
                    // fall-through to SELECT since the busy-wait is not supported with NIO

                case SelectStrategy.SELECT:
                    select(wakenUp.getAndSet(false));

                    // 'wakenUp.compareAndSet(false, true)' is always evaluated
                    // before calling 'selector.wakeup()' to reduce the wake-up
                    // overhead. (Selector.wakeup() is an expensive operation.)
                    //
                    // However, there is a race condition in this approach.
                    // The race condition is triggered when 'wakenUp' is set to
                    // true too early.
                    //
                    // 'wakenUp' is set to true too early if:
                    // 1) Selector is waken up between 'wakenUp.set(false)' and
                    //    'selector.select(...)'. (BAD)
                    // 2) Selector is waken up between 'selector.select(...)' and
                    //    'if (wakenUp.get()) { ... }'. (OK)
                    //
                    // In the first case, 'wakenUp' is set to true and the
                    // following 'selector.select(...)' will wake up immediately.
                    // Until 'wakenUp' is set to false again in the next round,
                    // 'wakenUp.compareAndSet(false, true)' will fail, and therefore
                    // any attempt to wake up the Selector will fail, too, causing
                    // the following 'selector.select(...)' call to block
                    // unnecessarily.
                    //
                    // To fix this problem, we wake up the selector again if wakenUp
                    // is true immediately after selector.select(...).
                    // It is inefficient in that it wakes up the selector for both
                    // the first case (BAD - wake-up required) and the second case
                    // (OK - no wake-up required).

                    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 {
                    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);
        }
    }
}

select之后处理发生的io事件或者任务,截止这里可以看到main线程启动里一个与NioServerSocketChannel关联的NioEventLoop中的线程并处理register

回到主线程 register 之后处理bind

private static void doBind0(
        final ChannelFuture regFuture, final Channel channel,
        final SocketAddress localAddress, final ChannelPromise promise) {

    // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up
    // the pipeline in its channelRegistered() implementation.
    channel.eventLoop().execute(new Runnable() { //交给eventLoop
        @Override
        public void run() {
            if (regFuture.isSuccess()) {
                channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            } else {
                promise.setFailure(regFuture.cause());
            }
        }
    });
}

调用unsafe的bind方法

 @Override
 public void bind(
         ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
         throws Exception {
     unsafe.bind(localAddress, promise);
 }

@Override
protected void doBind(SocketAddress localAddress) throws Exception {
    if (PlatformDependent.javaVersion() >= 7) {
        javaChannel().bind(localAddress, config.getBacklog());
    } else {
        javaChannel().socket().bind(localAddress, config.getBacklog());
    }
}

//绑定之后
 @Override
 protected void doBeginRead() throws Exception {
     // Channel.read() or ChannelHandlerContext.read() was called
     final SelectionKey selectionKey = this.selectionKey;
     if (!selectionKey.isValid()) {
         return;
     }

     readPending = true;

     final int interestOps = selectionKey.interestOps();
     if ((interestOps & readInterestOp) == 0) {
     	  //readInterestOp这个值在channel实例化的时候会被设置成accept
         selectionKey.interestOps(interestOps | readInterestOp);
     }
 }

然后主线程等待关闭 NioServerSocketChannel对应的eventLoop中的线程不断循环

当关注的accept事件发生

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;
		//取attachment 即NioServerSocketChannel
        final Object a = k.attachment();

        if (a instanceof AbstractNioChannel) {
        	//处理事件
            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;
        }
    }
}

区分不同事件,调用unsafe.read, 这个unsafe实例是NioServerSocketChannel的父类中的NioMessageUnsafe内部类,read方法中的doReadMessages作为一个模板方法,调用到NioServerSocketChannel中的doReadMessages

@Override
protected int doReadMessages(List<Object> buf) throws Exception {
    SocketChannel ch = SocketUtils.accept(javaChannel());

    try {
        if (ch != null) {
        	//构造函数中readInterestOp = SelectionKey.OP_READ
            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;
}

读取完之后触发pipeline的fireChannelRead方法,NioServerSocketChannel对应的pipeline为
HeadContext->ServerBootstrapAcceptor->TailContext
所以调用到ServerBootstrapAcceptor的channelRead方法

public void channelRead(ChannelHandlerContext ctx, Object msg) {
    final Channel child = (Channel) msg;
	
	//添加Handler
    child.pipeline().addLast(childHandler);

    setChannelOptions(child, childOptions, logger);

    for (Entry<AttributeKey<?>, Object> e: childAttrs) {
        child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
    }

    try {
    	//从workGroup线程组中取一个EventLoop关联NioSocketChannel
        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);
    }
}
发布了44 篇原创文章 · 获赞 13 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_19457117/article/details/84287102