netty处理客户端新连接源码分析

参考资料

Reactor(主从)原理详解与实现

NioEventLoopGroup源码分析

netty服务端启动流程源码分析

netty服务端启动流程总结

先看看图

在这里插入图片描述

NioEventLoop的run方法

//NioEventLoop的run方法主要是用来处理绑定的Channel的所有任务的
//1.轮训处理注册的Channel的IO事件
//2.轮训处理注册的Channel的所有异步任务,也就是任务队列里的操作
//3.NioEventLoop作为Boss EventLoop处理连接事件
//3.NioEventLoop作为Worker EventLoop处理读写事件
protected void run() {
    
    
    for (;;) {
    
    
      //省去无用代码....
      
       if (ioRatio == 100) {
    
    
                try {
    
    
                    //处理Selector上Channel的事件
                    processSelectedKeys();
                } finally {
    
    
                    //处理Selector上Channel的所有发生的异步任务,发生回调
                    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);
                }
            }
      
       //省去无用代码....
    }
}

NioEventLoop的processSelectedKeys方法

//处理Channel的IO事件的方法
private void processSelectedKeys() {
    
    
    if (selectedKeys != null) {
    
    
        processSelectedKeysOptimized();
    } else {
    
    
        processSelectedKeysPlain(selector.selectedKeys());
    }
}
//处理Channel的IO事件的方法
//1.获取到新连接Channel
//2.进一步处理新的Channel
private void processSelectedKeysOptimized() {
    
    
        for (int i = 0; i < selectedKeys.size; ++i) {
    
    
            final SelectionKey k = selectedKeys.keys[i];
            selectedKeys.keys[i] = null;

         		//获取到新的channel
            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);
            }
        }
}

//处理Channel上的事件
//对于服务端类型的父类通道,只会处理连接事件(SelectionKey.OP_ACCEPT)
private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
    
    
       
				省去无用代码....
  
        try {
    
    
            int readyOps = k.readyOps();
           
            if ((readyOps & SelectionKey.OP_WRITE) != 0) {
    
    
              
                ch.unsafe().forceFlush();
            }
            //处理读事件和连接事件
            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
    
    
                //使用channel绑定的unsafe来操作读和连接事件
                unsafe.read();
            }
        } catch (CancelledKeyException ignored) {
    
    
            unsafe.close(unsafe.voidPromise());
        }
    }
  
  

NioMessageUnsafe的read方法

//处理NIO事件的类
private final class NioMessageUnsafe extends AbstractNioUnsafe {
    
    

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

  //处理读事件方法
    @Override
    public void read() {
    
    
        
        //获取Channel相关的pipeline,如果是父通道,那么里面有注册时候绑定的
       //ServerBootstrapAcceptor的处理器
        final ChannelPipeline pipeline = pipeline();
       
            int size = readBuf.size();
            for (int i = 0; i < size; i ++) {
    
    
                readPending = false;
                //开始使用通道绑定的pipeline处理新连接
                pipeline.fireChannelRead(readBuf.get(i));
            }   
    }
}

DefaultChannelPipeline的fireChannelRead方法

//Pipeline处理器链的入口,责任链模式的典型
public final ChannelPipeline fireChannelRead(Object msg) {
    
    
    AbstractChannelHandlerContext.invokeChannelRead(head, msg);
    return this;
}

//从Pipeline的头Hadler开始处理
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
    
    
        final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
        //获取下一个Hadler
  			EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
    
    
            //不断执行下一个Hadler,这里会到我们绑定的ServerBootstrapAcceptor进行处理
            next.invokeChannelRead(m);
        } else {
    
    
            executor.execute(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    next.invokeChannelRead(m);
                }
            });
        }
    }
    
//开始真正Hadler的处理流程
    private void invokeChannelRead(Object msg) {
    
    
        if (invokeHandler()) {
    
    
            try {
    
    
                ((ChannelInboundHandler) handler()).channelRead(this, msg);
            } catch (Throwable t) {
    
    
                notifyHandlerException(t);
            }
        } else {
    
    
            fireChannelRead(msg);
        }
    }

ServerBootstrapAcceptor的channelRead方法

//处理新连接的真正核心方法,因为是传输类型通道,那么其实是注册到childGroup的,这个需要注意
//1.使用worker EventLoopGroup上的EventLoop进行注册新的Channel
//2.可以体会到连接和读写事件使用的 EventLoopGroup是区分了的
//3.注册新通道后,和之前注册服务端通道做的事情是一样的(注册事件不一样)
//  a.将新通道绑定到相应的EventLoop上
//  b.注册读写事件
//  c.绑定相关自定义的处理器到Pipeline
//  d.启动EventLoop线程,进行轮训处理子通道的读写事件  
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    
    
   
    try {
    
    
        //使用worker EventLoopGroup上的EventLoop进行注册新的Channel
        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);
    }
}

总结

新客户端连接整个流程就是boss和worker之间如何交互,woker里面的eventLoop如何初始化,注册,也说明了worker的一个触发时机

猜你喜欢

转载自blog.csdn.net/weixin_38312719/article/details/108619964