Netty事件循环主逻辑NioEventLoop的run方法分析

网友投稿 728 2022-10-17

Netty事件循环主逻辑NioEventLoop的run方法分析

Netty事件循环主逻辑NioEventLoop的run方法分析

目录Netty事件循环主逻辑初始化 EventLoop处理读事件注意

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-ty.noKeySetOptimization ,默认是 false 代表开启

private static final boolean DISABLE_KEYSET_OPTIMIZATION =

SystemPropertyUtil.getBoolean("io-ty.noKeySetOptimization", false);

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

初始化 EventLoop

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

private SelectorTuple openSelector() {

12      //注入逻辑40

Object maybeException = AccessController.doPrivileged(new PrivilegedAction() {

@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 &lthttp://; 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 task = (NioTask) 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 triggerOyuOxq 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)  -> ServerBootstrapAcceptor.channelRead ,

将受到的 NioSocketChannel 注册到 childEventLoop 。

以上就是Netty事件循环主逻辑NioEventLoop的run方法分析的详细内容,更多关于Netty循环逻辑NioEventLoop run方法的资料请关注我们其它相关文章!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:eggjs 怎么实现用户注册功能?
下一篇:SAM .OpenResty- SAM 隔离框架
相关文章

 发表评论

暂时没有评论,来抢沙发吧~