文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

NioEventLoop的run方法实例分析

2023-06-29 15:44

关注

这篇文章主要介绍了NioEventLoop的run方法实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇NioEventLoop的run方法实例分析文章都会有所收获,下面我们一起来看看吧。

Netty事件循环主逻辑

Netty 事件循环主逻辑在 NioEventLoop.run 中的 processSelectedKeys函数中

protected void run() {      //主循环不断读取IO事件和task,因为 EventLoop 也是 juc 的 ScheduledExecutorService 实现        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;            // IO事件占总执行时间的百分比 */                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);            }        }    }

processSelectedKeys 函数 执行时会判断是否执行优化的版本,即判断 SelectedSelectionKeySet 是否为空。

是否开启优化取决于是否设置了环境变量  io.netty.noKeySetOptimization ,默认是 false 代表开启

private static final boolean DISABLE_KEYSET_OPTIMIZATION =            SystemPropertyUtil.getBoolean("io.netty.noKeySetOptimization", false);

原理是通过反射的方式设置 eventLoop绑定的selector中的 selectKeys属性 为 SelectedSelectionKeySet ,好处是不用 迭代  selector.selectedKeys()

初始化 EventLoop

注入时机为初始化 EventLoop 的时候

private SelectorTuple openSelector() {        12      //注入逻辑40         Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {            @Override            public Object run() {                try {                    Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");                    Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");                    Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField);                    if (cause != null) {                        return cause;                    }                    cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField);                    if (cause != null) {                        return cause;                    }                    selectedKeysField.set(unwrappedSelector, selectedKeySet);                    publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);                    return null;                } catch (NoSuchFieldException e) {                    return e;                } catch (IllegalAccessException e) {                    return e;                }            }        });        ........78     }

处理读事件

处理读事件主要在processSelectedKey 中 ,分别对 读、写、连接事件进行了处理。

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;            final Object a = k.attachment();            if (a instanceof AbstractNioChannel) {                //分别处理每个channel的事件                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;            }        }    }    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
 //将要写入的buffer flush掉          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) {           //回调 pipeline 上所有的 ChannelInboundHandler 的 fireChannelRead  和 channelReadComplete 函数                unsafe.read();            }        } catch (CancelledKeyException ignored) {            unsafe.close(unsafe.voidPromise());        }    }

注意 

NioServerSocketChannel 和 NioSocketChannel 都是 同样的 处理逻辑, 不同的是  前者 只关注 OP_ACCEPT 和 OP_READ事件, 后者 关注  OP_READ、OP_WRITE、OP_CONNECT事件

当NioServerSocketChannel 发生 OP_ACCEPT事件时 会 触发

 AbstractNioChannel.NioUnsafe.read ->  NioSctpServerChannel.doReadMessages(List<Object>)  -> ServerBootstrapAcceptor.channelRead ,

将受到的 NioSocketChannel 注册到 childEventLoop 。

关于“NioEventLoop的run方法实例分析”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“NioEventLoop的run方法实例分析”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯