netty5笔记-总体流程分析3-NioServerSocketChannel

        前面我们讲了server的启动过程,同时介绍了其中非常重要的几个概念,ChannelPipeline,ChannelHandlerContext等。接下来我们看看server启动起来以后是如何运转的。

        先回忆下之前的几个重要的点,如果要监听某个端口,首先用ServerBootstrap引导启动,启动时创建一个ServerSocketChannel,并注册到bossGroup的EventLoop中,关注的事件为OP_ACCEPT。boss EventLoop开始运行,并不停的尝试从Selector中查看是否有准备好的连接。由于ServerSocketChannel关注的是OP_ACCEPT,因此每当有客户端连接到服务端的时候,boss EventLoop都可以select到一个SelectionKey,然后进入以下方法:

    //NioEventLoop
    private static void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
        final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
        if (!k.isValid()) {
            // 如果key无效了则关闭连接
            unsafe.close(unsafe.voidPromise());
            return;
        }

        try {
            int readyOps = k.readyOps();
            // 检查readOps,避免由jdk bug导致readOps为0而产生自旋(cpu 100%)
            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                // 调用unsafe.read方法,这个也是我们今天分析的入口
                unsafe.read();
                if (!ch.isOpen()) {
                    // 连接已经关闭则直接返回,就不用处理后面的write事件了
                    return;
                }
            }
            。。。省略不会触发的几句代码。。。
            if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
                // 取消此key对 OP_CONNECT的关注,否则Selector.select(..)不会阻塞而直接返回,导致cpu 100%
                // 此bug见 https://github.com/netty/netty/issues/924
                int ops = k.interestOps();
                ops &= ~SelectionKey.OP_CONNECT;
                k.interestOps(ops);

                unsafe.finishConnect();
            }
        } catch (CancelledKeyException ignored) {
            unsafe.close(unsafe.voidPromise());
        }
    }
         注意还有一种情况是processSelectedKey(SelectionKey k, NioTask<SelectableChannel> task),这是扩展的情况,暂时无人实现,先不分析。

         这里引出了本次分析的第一个入口点,ch.unsafe().read()。NioServerSocketChannel对应的unsafe实现为NioMessageUnsafe,我们来看看它的read方法做了哪些事情(去掉部分无关代码):

        // NioMessageUnsafe
        private final List<Object> readBuf = new ArrayList<Object>();

        public void read() {
            final ChannelConfig config = config();
            // 下面有个循环操作,这里的值代表循环的最大次数,对于NioServerSocketChannel来说也就是单次最大接受的连接数,默认为16,
            // 可以在启动的时候通过初始化时调用引导类的setOption(ChannelOption.MAX_MESSAGES_PER_READ, 32)修改这个值。
            final int maxMessagesPerRead = config.getMaxMessagesPerRead();
            final ChannelPipeline pipeline = pipeline();
            boolean closed = false;
            Throwable exception = null;
            try {
                try {
                    for (;;) {
                        // 此处会调用到NioServerSocketChannel中的doReadMessages方法
                        int localRead = doReadMessages(readBuf);
                        // 读到的值为0没获取到连接(可能是已经关闭了),注意NioServerSocketChannel中的doReadMessages只会返回0,1,   
                        // -1在其他场景中出现,后面再分析                    
                        if (localRead == 0) {
                            break;
                        }
                        
                        // 每次读取成功readBuf中就会多一个连接,达到阈值则先跳出循环,剩下的数据下次循环时再取
                        if (readBuf.size() >= maxMessagesPerRead) {
                            break;
                        }
                    }
                } catch (Throwable t) {
                    exception = t;
           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值