Netty学习笔记七Netty源码

8 篇文章 0 订阅
8 篇文章 0 订阅

Netty学习笔记七

七. Netty源码

写的比较乱,请见谅。

1. 启动剖析

Nio流程

// 1. 创建Selector
Selector selector = Selector.open();     

// 2. 创建serverSocketChannel
ServerSocketChannel ssc = ServerSocketChannel.open();  

// 3. 将serverSocketChannel注册到selector上
SelectionKey selectionKey = ssc.register(selector, 0, nettySsc); 

// 4. 绑定监听端口
ssc.bind(new InetSocketAddress(9090, backlog));

// 5. 设置感兴趣的事件   
selectionKey.interestOps(SelectionKey.OP_ACCEPT);
   

Netty 流程简略分析

//1 netty 中使用 NioEventLoopGroup (简称 nio boss 线程)来封装线程和 selector
Selector selector = Selector.open(); 

//2 创建 NioServerSocketChannel,同时会初始化它关联的 handler,以及为原生 ssc 存储 config
NioServerSocketChannel attachment = new NioServerSocketChannel();

//3 创建 NioServerSocketChannel 时,创建了 java 原生的 ServerSocketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); 
serverSocketChannel.configureBlocking(false);

//4 启动 nio boss 线程执行接下来的操作

//5 注册(仅关联 selector 和 NioServerSocketChannel),未关注事件
SelectionKey selectionKey = serverSocketChannel.register(selector, 0, attachment);

//6 head -> 初始化器 -> ServerBootstrapAcceptor -> tail,初始化器是一次性的,只为添加 acceptor

//7 绑定端口
serverSocketChannel.bind(new InetSocketAddress(8080));

//8 触发 channel active 事件,在 head 中关注 op_accept 事件
selectionKey.interestOps(SelectionKey.OP_ACCEPT);

bind方法概述

服务端代码

package com.sunyang.netty.study.nettydemo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;

/**
 * @program: netty-study
 * @description: 源码分析
 * @author: SunYang
 * @create: 2021-08-25 13:52
 **/

public class NettySourceServer {
    public static void main(String[] args) {
        new ServerBootstrap()
                .group(new NioEventLoopGroup()) //  Selector selector = Selector.open(); 
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>(){
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new LoggingHandler());
                    }
                }).bind(8080);
    }
}

【AbstractBootstrap.java】

public ChannelFuture bind(int inetPort) {
    return bind(new InetSocketAddress(inetPort));
}
public ChannelFuture bind(SocketAddress localAddress) {
        validate();
        return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}

private ChannelFuture doBind(final SocketAddress localAddress) {
    	// init ----> ServerSocketChannel ssc = ServerSocketChannel.open()  main主线程
    	// Register ---> SelectionKey selectionKey = ssc.register(selector, 0, nettySsc);由Nio线程去执行 
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }

        if (regFuture.isDone()) {
            // 进入此处说明我们知道初始化和注册完成并成功。
            ChannelPromise promise = channel.newPromise();
            // 同步执行dobind0方法,由main线程
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {
           // 进入此处说明还没注册完成就会由Nio线程进行异步调用dobind0
            // 由于注册耗时时间较长,所以很大几率是进入此处,由Nio线程回调doBind0去执行
            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
            // 异步去执行doBind0 由Nio线程去执行
            // serverSocketChannel.bind(new InetSocketAddress(8080));
            regFuture.addListener(new ChannelFutureListener() {
                // 此处回调dobind0;
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if (cause != null) {
                       
                        promise.setFailure(cause);
                    } else {
                       
                        promise.registered();
						
                        doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
}

image-20210825141838260

initAndRegister()

final ChannelFuture initAndRegister() {
    Channel channel = null;
    //  1. init 创建channel 并初始化handler
    try {
    	// 1.1 创建 channel
        channel = channelFactory.newChannel();
    	// 1.2 初始化handler     
        init(channel);
    } catch (Throwable t) {
        if (channel != null) {
            channel.unsafe().closeForcibly();
            return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
        }
        return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
    }
    
    
    
// 2. register 注册channel
    ChannelFuture regFuture = config().group().register(channel);
    if (regFuture.cause() != null) {
        if (channel.isRegistered()) {
            channel.close();
        } else {
            channel.unsafe().closeForcibly();
        }
    }
    return regFuture;
}
1.1 channel = channelFactory.newChannel();
public T newChannel() {
    try {
        // 利用反射获取构造器创建实例
        return constructor.newInstance();
    } catch (Throwable t) {
        throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
    }
}

 public NioServerSocketChannel() {
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
 }

private static ServerSocketChannel newSocket(SelectorProvider provider) {
        try {
            /**
             *  Use the {@link SelectorProvider} to open {@link SocketChannel} and so remove condition in
             *  {@link SelectorProvider#provider()} which is called by each ServerSocketChannel.open() otherwise.
             *
             *  See <a href="https://github.com/netty/netty/issues/2308">#2308</a>.
             */
            // 创建了一个原生的ServerSocketChannel 
            // 等于Nio中的ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()
            return provider.openServerSocketChannel();
        } catch (IOException e) {
            throw new ChannelException(
                    "Failed to open a server socket.", e);
        }
    }

image-20210825143723149

1.2 init(channel)
@Override
void init(Channel channel) {
    setChannelOptions(channel, newOptionsArray(), logger);
    setAttributes(channel, newAttributesArray());

    ChannelPipeline p = channel.pipeline();

    final EventLoopGroup currentChildGroup = childGroup;
    final ChannelHandler currentChildHandler = childHandler;
    final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
    final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
	
    // 在流水线中添加了一个(ChannelInitializer<Channel>)handler他只会执行一次,这次只是加入到流水上,并没有执行initChannel(). 
    p.addLast(new ChannelInitializer<Channel>() {
        @Override
        public void initChannel(final Channel ch) {
            final ChannelPipeline pipeline = ch.pipeline();
            ChannelHandler handler = config.handler();
            if (handler != null) {
                pipeline.addLast(handler);
            }
			// 保证此任务也在NIo线程中执行。
            ch.eventLoop().execute(new Runnable() {
                @Override
                public void run() {
                    // 向NioServerSocketChannel中加入了Acceptor handler (在accept事件发生后建立连接。)
                    pipeline.addLast(new ServerBootstrapAcceptor(
                            ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                }
            });
        }
    });
}

image-20210825144152246

2.1 config().group().register(channel);
@Override
public ChannelFuture register(Channel channel) {
    return next().register(channel);
}
@Override
    public ChannelFuture register(Channel channel) {
        return register(new DefaultChannelPromise(channel, this));
}

@Override
public ChannelFuture register(final ChannelPromise promise) {
        ObjectUtil.checkNotNull(promise, "promise");
        promise.channel().unsafe().register(this, promise);
        return promise;
}
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
    ObjectUtil.checkNotNull(eventLoop, "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;

    // 之前都是在main线程中执行, 在这里要进行线程切换
    // 判断当前线程是否是Nio线程,当前为main线程,所以会进入到else中
    if (eventLoop.inEventLoop()) {
        register0(promise);
    } else {
        try {
            // 将register0 封装到任务对象中,然后交给EventLoop去执行。
            // 懒加载,调用execute时才会创建Nio Boss线程。
            eventLoop.execute(new Runnable() {
                @Override
                public void run() {
                    // 切换成NIo 线程,执行此方法
                    register0(promise);
                }
            });
        } 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);
        }
    }
}
private void register0(ChannelPromise promise) {
    try {
      
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
            return;
        }
        boolean firstRegistration = neverRegistered;
        // 执行doRegister
        doRegister();
        neverRegistered = false;
        registered = true;
		// 注册完毕后调用
		// 调用初始化handler(就是上一步只是添加了,但是未执行初始化。) 的initChannel 方法()
        pipeline.invokeHandlerAddedIfNeeded();
		
        // 给promise设置成功的结果。然后主线程哪里就可以通过回调获得结果。
        safeSetSuccess(promise);
        pipeline.fireChannelRegistered();
      
        if (isActive()) {
            if (firstRegistration) {
                pipeline.fireChannelActive();
            } else if (config().isAutoRead()) {
              
                beginRead();
            }
        }
    } catch (Throwable t) {
       
        closeForcibly();
        closeFuture.setClosed();
        safeSetFailure(promise, t);
    }
}
protected void doRegister() throws Exception {
    boolean selected = false;
    for (;;) {
        try {
            //  SelectionKey selectionKey = ssc.register(selector, 0, nettySsc
            // 并未关联事件
            selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
            return;
        } catch (CancelledKeyException e) {
            if (!selected) {
                
                eventLoop().selectNow();
                selected = true;
            } else {
      
                throw e;
            }
        }
    }
}

doBind0()

private static void doBind0(
        final ChannelFuture regFuture, final Channel channel,
        final SocketAddress localAddress, final ChannelPromise promise) {
    channel.eventLoop().execute(new Runnable() {
        @Override
        public void run() {
            if (regFuture.isSuccess()) {
                channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            } else {
                promise.setFailure(regFuture.cause());
            }
        }
    });
}
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
    assertEventLoop();

    if (!promise.setUncancellable() || !ensureOpen(promise)) {
        return;
    }

    // See: https://github.com/netty/netty/issues/576
    if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) &&
        localAddress instanceof InetSocketAddress &&
        !((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() &&
        !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
        // Warn a user about the fact that a non-root user can't receive a
        // broadcast packet on *nix if the socket is bound on non-wildcard address.
        logger.warn(
                "A non-root user can't receive a broadcast packet if the socket " +
                "is not bound to a wildcard address; binding to a non-wildcard " +
                "address (" + localAddress + ") anyway as requested.");
    }

    boolean wasActive = isActive();
    try {
        // 端口号的绑定
        doBind(localAddress);
    } catch (Throwable t) {
        safeSetFailure(promise, t);
        closeIfClosed();
        return;
    }
	// 判断端口是否可用
    if (!wasActive && isActive()) {
        invokeLater(new Runnable() {
            @Override
            public void run() {
                // 触发流水线上的每个handler的active事件
                pipeline.fireChannelActive();
            }
        });
    }

    safeSetSuccess(promise);
}
protected void doBind(SocketAddress localAddress) throws Exception {
    if (PlatformDependent.javaVersion() >= 7) {
    	// 进行端口绑定,并设置全连接队列大小。
        javaChannel().bind(localAddress, config.getBacklog());
    } else {
        javaChannel().socket().bind(localAddress, config.getBacklog());
    }
}
public void channelActive(ChannelHandlerContext ctx) 
    // 关注accept事件
    ctx.fireChannelActive();

    readIfIsAutoRead();
}
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) {
    // 关注accept事件。
        selectionKey.interestOps(interestOps | readInterestOp);
    }
}

至此执行结束

执行图

image-20210825153810485

NioEventLoop

image-20210825154021129

1)组成

// NioEventLoop.java
private Selector selector;
private Selector unwrappedSelector;

// 父类 SingleThreadEventExecutor.java

 private final Queue<Runnable> taskQueue; // 任务队列 ,单线程所以如果有多个任务,就需要任务队列

private volatile Thread thread; // 线程
private final Executor executor; // 单线程的执行器,可以理解为单线程的线程池。可以提交任务和添加定时任务 。和上面的线程是一个线程,只不过这个功能多。

// 曾祖父类 AbstractScheduledEventExecutor.java
PriorityQueue<ScheduledFutureTask<?>> scheduledTaskQueue; // 处理定时任务的任务队列

2)selector何时创建

在构造方法调用时

NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
             SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,
             EventLoopTaskQueueFactory taskQueueFactory, EventLoopTaskQueueFactory tailTaskQueueFactory) {
    super(parent, executor, false, newTaskQueue(taskQueueFactory), newTaskQueue(tailTaskQueueFactory),
            rejectedExecutionHandler);
    this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider");
    this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy");
    final SelectorTuple selectorTuple = openSelector(); // 此处创建
    this.selector = selectorTuple.selector;
    this.unwrappedSelector = selectorTuple.unwrappedSelector;
}
2.1 为什么会有两个selector
private Selector selector;
private Selector unwrappedSelector;

为了在遍历selectedKeys提高性能,进行优化,JDK的selectedKeys是用set存储的,遍历性能差,而Netty用的是数组。

3)EventLoop的Nio线程在何时启动

当首次调用execute方法时会启动EventLoop的Nio线程,并且只会启动一次。

通过状态位控制线程不会被重复启动。

package com.sunyang.netty.study.nettydemo;

import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoopGroup;

/**
 * @program: netty-study
 * @description: EventLoop何时启动
 * @author: SunYang
 * @create: 2021-08-25 16:41
 **/
public class EventLoopStartDemo {
    public static void main(String[] args) {
        EventLoop eventLoop = new NioEventLoopGroup().next();
        // 在第一次调用execute时被创建
        eventLoop.execute(() -> {
            System.out.println("hello");
        });
    }
}
private void doStartThread() {
    assert thread == null;
    // 执行器(单线程的线程池) Nio线程
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // 将当前执行器中的线程(就是Nio线程)赋值给了thread
            thread = Thread.currentThread();
            if (interrupted) {
                thread.interrupt();
            }
             boolean success = false;
                updateLastExecutionTime();
                try {
                    // NioEventLoop的run() 方法  
                    // 死循环去查看有没有任务,定时任务,IO事件。
                    SingleThreadEventExecutor.this.run();
                    success = true;
                } catch (Throwable t) {
                    logger.warn("Unexpected exception from an event executor: ", t);
                ......

image-20210825165058267

4)提交普通任务会不会结束select阻塞。

Netty底层使用的是带超时的select(timeoutMillis)方法,时间到了会结束阻塞

提交普通任务的时候也会调用selectot.wakeup()方法,所以会结束阻塞,并执行普通任务。

4.1 wakeup方法中的代码如何理解
protected void wakeup(boolean inEventLoop) {
    // 1. 当前执行提交任务的线程(执行wakeup的线程)和我EventLoop中的Nio线程是否是同一个线程,也就是只有其他线程提交任务时,才会唤醒selector,如果是Nio线程自己,并不需要唤醒,因为在EventLoop内部自己有唤醒机制。
    // 2. wakenUp 原子布尔变量,用CAS设置值,作用
    if (!inEventLoop && wakenUp.compareAndSet(false, true)) { // 4.1.39版本
            selector.wakeup();
        }
    if (!inEventLoop && nextWakeupNanos.getAndSet(AWAKE) != AWAKE) { // 4.1.66 版本
        selector.wakeup();
    }
}
4.2 wakenUp变量的作用是什么

因为wakeUp是个重量级操作。

如果有多个其他线程都来提交任务,为了避免频繁调用wakeUp方法,所以用原子变量来控制在多线程情况下只有一个线程能成功调用wakeUp()方法。

5)每次循环时,什么时候会进入SelectStrategy.SELECT分支,让select进入阻塞。

当没有任务时,才会进入SelectStrategy.SELECT分支

当有任务时,会调用selectNow()方法(顺便拿到IO事件), 然后执行普通任务和IO事件。

protected void run() {
    for (;;) {
        try {
            try {
                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));
                    ....
public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {
    return hasTasks ? selectSupplier.get() : SelectStrategy.SELECT;
}
private final IntSupplier selectNowSupplier = new IntSupplier() {
    @Override
    public int get() throws Exception {
        return selectNow();
    }
};
5.1 select()方法会阻塞多久

没有任务时会进入阻塞,默认阻塞 1.5秒左右,

什么情况下会退出阻塞:

  • 超时时间到了
  • 有任务了
  • 有事件发生了
private void select(boolean oldWakenUp) throws IOException {
    Selector selector = this.selector;

    try {
        int selectCnt = 0;
        long currentTimeNanos = System.nanoTime();
        long selectDeadLineNanos = currentTimeNanos + this.delayNanos(currentTimeNanos);

        while(true) {
            long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;
            // 什么时候退出此循环 当 超时时间过了,timeoutMillis为0或小于0时,就会结束循环,也就是结束阻塞
            if (timeoutMillis <= 0L) {
                if (selectCnt == 0) {
                    selector.selectNow();
                    selectCnt = 1;
                }
                break;
            }
            // 有任务时 ,也会退出循环。结束阻塞。
             if (this.hasTasks() && this.wakenUp.compareAndSet(false, true)) {
                    selector.selectNow();
                    selectCnt = 1;
                    break;
                }
            
            // 有时间发生时。
            int selectedKeys = selector.select(timeoutMillis);
              ++selectCnt;
                if (selectedKeys != 0 || oldWakenUp || this.wakenUp.get() || this.hasTasks() || this.hasScheduledTasks()) {
                    break;
                }
            currentTimeNanos = time;
       ....
        }

}

超时时间计算

long currentTimeNanos = System.nanoTime();
//   截止时间  			  =   当前时间  	  +  返回的时间 1秒(没有定时任务时)	
long selectDeadLineNanos = currentTimeNanos + delayNanos(currentTimeNanos);

for (;;) {
    // 超时时间  		=   截止时间 			- 当前时间   		 + 0.5 毫秒	= 1.5 秒
    long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;
protected long delayNanos(long currentTimeNanos) {
    ScheduledFutureTask<?> scheduledTask = peekScheduledTask();
    // 如果没有定时任务,返回一个时间
    if (scheduledTask == null) {
        return SCHEDULE_PURGE_INTERVAL; // 1秒
    }
	// 如果有定时任务,返回下一个定时任务的执行时间
    return scheduledTask.delayNanos(currentTimeNanos);
}

6)Nio空轮询BUG

JDK在Linux的selector下才会发生

Netty的解决方法

通过设置一个计数器,count(阈值) 来判断是否发生了空轮询,默认512 ,可以自己设置。

解决:重新创建一个selector。替换掉了旧的selector。

7)ioRatio控制什么,设置为100有何作用

ioRatio控制处理IO事件所占用的时间比例。默认50%。

如果把ioRatio设置为100,就是所有IO事件执行完,再执行普通任务,但是下一次IO事件就要等到所有的普通任务执行完。所以不要设置成100、

protected void run() {
    for (;;) {
        try {
            try {
                switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
                case SelectStrategy.CONTINUE:
                    continue;

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

                    if (wakenUp.get()) {
                        selector.wakeup();
                    }
                    // fall through
                default:
                }
            } catch (IOException e) {
              
                rebuildSelector0();
                handleLoopException(e);
                continue;
            }

            cancelledKeys = 0;
            needsToSelectAgain = false;
            final int ioRatio = this.ioRatio;
            if (ioRatio == 100) {
                try {
                    processSelectedKeys();
                } finally {
                    // Ensure we always run tasks.
                    runAllTasks();
                }
            } else {
                // 记录执行IO事件的开始时间
                final long ioStartTime = System.nanoTime();
                try {
                    // 处理所有IO事件。
                    processSelectedKeys();
                } finally {
                    // ioTime代表执行IO事件处理所耗费的时间。 
                    final long ioTime = System.nanoTime() - ioStartTime;
                    // 然后处理所有普通任务。如果处理普通任务的时间过长,就会影响IO事件处理效率
              
                    runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
                }
            }
        } catch (Throwable t) {
            handleLoopException(t);
        }
}

8) selectedKeys集合优化

private void processSelectedKeys() 
    // 判断是否为空
    if (selectedKeys != null) {
        // 如果不为null, 证明Netty已经把selectedKeys集合底层替换掉了
        processSelectedKeysOptimized();
    } else {
        // 如果不为null 走原始的selectedKeys集合
        processSelectedKeysPlain(selector.selectedKeys());
    }
}
private void processSelectedKeysOptimized() {
    for (int i = 0; i < selectedKeys.size; ++i) {
        final SelectionKey k = selectedKeys.keys[i];
        // 拿到事件
        selectedKeys.keys[i] = null;
		// 拿到key上关联的附件(NioServerSocketChannel或NioSocketChannel)
        // 要对key进行各种各样的处理(读,写等等),对这些处理就需要用到handler,所以通过附件拿到channel,然后拿到handler,进行处理。
        final Object a = k.attachment();

        if (a instanceof AbstractNioChannel) {
            // 然后进行事件区分 - 9
            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;
        }
    }
}

9)在哪里区分不同事件类型。

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) {
          
            return;
        }
     
        if (eventLoop != this || eventLoop == null) {
            return;
        }
    
        unsafe.close(unsafe.voidPromise());
        return;
    }

    try {
      	// 是否是连接事件
        if ((readyOps & SelectionKey.OP_CONNECT) != 0) {

            int ops = k.interestOps();
            ops &= ~SelectionKey.OP_CONNECT;
            k.interestOps(ops);

            unsafe.finishConnect();
        }

        // 是否是写事件
        if ((readyOps & SelectionKey.OP_WRITE) != 0) {
           
            ch.unsafe().forceFlush();
        }
		
        // 是否是可读事件或者可连接事件
        if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
            unsafe.read();
        }
    } catch (CancelledKeyException ignored) {
        unsafe.close(unsafe.voidPromise());
    }
}

accept() 流程

NIO的Accept() 流程

image-20210825192814474

Netty流程

image-20210825201008248

前三步已经在EventLoop中执行完了

// 是否是可读事件或者可连接事件
        if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
            unsafe.read(); // 将会把后面三件事执行完毕
        }

执行到此,继续向下执行

public void read() {
        assert eventLoop().inEventLoop();
        final ChannelConfig config = config();
        final ChannelPipeline pipeline = pipeline();
        final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
        allocHandle.reset(config);

        boolean closed = false;
        Throwable exception = null;
        try {
            try {
                do {
                   // 创建SocketChannel,设置非阻塞
                    int localRead = doReadMessages(readBuf);
                    if (localRead == 0) {
                        break;
                    }
                    if (localRead < 0) {
                        closed = true;
                        break;
                    }

                    allocHandle.incMessagesRead(localRead);
                } while (allocHandle.continueReading());
            } catch (Throwable t) {
                exception = t;
            }

            int size = readBuf.size();
            for (int i = 0; i < size; i ++) {
                readPending = false;
                // 拿到NioServerSocketChannel上的流水线,然后将刚刚建立的连接当成消息进行处理。
                // ServerSocketChannel上的流水线 就只包括三个Handler head->acceptor->tail
                // 然后由acceptor处理剩下的步骤:将SocketChannel注册至selector和关注read事件
                pipeline.fireChannelRead(readBuf.get(i));
            }
            readBuf.clear();
            allocHandle.readComplete();
            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();
            }
        }
    }
}
protected int doReadMessages(List<Object> buf) throws Exception {
    // 调用ServerSocketChannel.accept() 建立连接完毕 
    SocketChannel ch = SocketUtils.accept(javaChannel());

    try {
        if (ch != null) {
            // 创建NioSocketChannel,并将建立连接的原生SocketChannel作为构造方法的参数传给了NioSocketChannel并设置为非阻塞
            // 将NioSocketChannel当成一个消息,放到一个结果里,然后在handler中进行处理
            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;
}
private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        final Channel child = (Channel) msg;

        child.pipeline().addLast(childHandler);

        setChannelOptions(child, childOptions, logger);

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

        try {
            // 要把一个新的NioEventLoop中的selector和NioSocketChannel进行绑定并监听事件。
            // 并用这个NioEventLoop中的那个线程去执行NioSocketChannel的事件任务,因为执行当前accept事件的线程是NioServerSocketChannel的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);
        }
    }
}
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
    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()) {
                    register0(promise);
                } else {
                    try {
                        // 
                        eventLoop.execute(new Runnable() {
                            @Override
                            public void run() {
                                // 执行注册操作
                                register0(promise);
                            }
                        });
                    } 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);
                    }
                }
            }
}
private void register0(ChannelPromise promise) {
    try {
        // check if the channel is still open as it could be closed in the mean time when the register
        // call was outside of the eventLoop
        if (!promise.setUncancellable() || !ensureOpen(promise)) {
            return;
        }
        boolean firstRegistration = neverRegistered;
        // 执行 注册操作  将SocketChannel注册至selector
        doRegister();
        neverRegistered = false;
        registered = true;

       	// 触发ScoketChannel上的初始化事件ininChannel()
        pipeline.invokeHandlerAddedIfNeeded();

        safeSetSuccess(promise);
        pipeline.fireChannelRegistered();
      
        if (isActive()) {
            if (firstRegistration) {
                // 关注read事件
                pipeline.fireChannelActive();
            } else if (config().isAutoRead()) {
        
                beginRead();
            }
        }
    } catch (Throwable t) {
        // Close the channel directly to avoid FD leak.
        closeForcibly();
        closeFuture.setClosed();
        safeSetFailure(promise, t);
    }
}
protected void doRegister() throws Exception {
    boolean selected = false;
    for (;;) {
        try {
        // 将原生的SocketChannel注册到eventLoop的selector上,并将NIoSocketChannel当作附件绑定
            selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
            return;
        } catch (CancelledKeyException e) {
            if (!selected) {
                // Force the Selector to select now as the "canceled" SelectionKey may still be
                // cached and not removed because no Select.select(..) operation was called yet.
                eventLoop().selectNow();
                selected = true;
            } else {
                // We forced a select operation on the selector before but the SelectionKey is still cached
                // for whatever reason. JDK bug ?
                throw e;
            }
        }
    }
}

read()流程

NIO的read() 流程

image-20210825201215388

Netty的read() 流程

在此开始

// 是否是可读事件或者可连接事件
        if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
            unsafe.read(); 
        }
public abstract class AbstractNioByteChannel extends AbstractNioChannel { 
    public final void read() {
            final ChannelConfig config = config();
            if (shouldBreakReadReady(config)) {
                clearReadPending();
                return;
            }
            final ChannelPipeline pipeline = pipeline();
            final ByteBufAllocator allocator = config.getAllocator();
            final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
            allocHandle.reset(config);

            ByteBuf byteBuf = null;
            boolean close = false;
            try {
                do {
                    // 分配ByteBuf
                    byteBuf = allocHandle.allocate(allocator);
                    // 从网络中读取数据
                    allocHandle.lastBytesRead(doReadBytes(byteBuf));
                    if (allocHandle.lastBytesRead() <= 0) {
                        // nothing was read. release the buffer.
                        byteBuf.release();
                        byteBuf = null;
                        close = allocHandle.lastBytesRead() < 0;
                        if (close) {
                            // There is nothing left to read as we received an EOF.
                            readPending = false;
                        }
                        break;
                    }

                    allocHandle.incMessagesRead(1);
                    readPending = false;
                    // 找到流水线,触发读事件,然后将数据依次传给handler,进行处理
                    pipeline.fireChannelRead(byteBuf);
                    byteBuf = null;
                } while (allocHandle.continueReading());

                allocHandle.readComplete();
                pipeline.fireChannelReadComplete();

                if (close) {
                    closeOnRead(pipeline);
                }
            } catch (Throwable t) {
                handleReadException(pipeline, byteBuf, t, close, allocHandle);
            } 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();
                }
            }
        }
    }
}
      allocHandle.incMessagesRead(1);
                readPending = false;
                // 找到流水线,触发读事件,然后将数据依次传给handler,进行处理
                pipeline.fireChannelRead(byteBuf);
                byteBuf = null;
            } while (allocHandle.continueReading());

            allocHandle.readComplete();
            pipeline.fireChannelReadComplete();

            if (close) {
                closeOnRead(pipeline);
            }
        } catch (Throwable t) {
            handleReadException(pipeline, byteBuf, t, close, allocHandle);
        } 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();
            }
        }
    }
}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值