Netty源码阅读4——连接建立

Posted by 皮皮潘 on 12-05,2021

NioServerSocketChannel本质上也是通过调用read方法进行连接的建立以及NioSocketChannel的创建与注册的,只是与NioSocketChannel的read方法相比较,前者传输的参数的具体类型是NioSocketChannel,而后者传输的参数的具体类型是ByteBuf,这是因为前者继承的是AbstractNioMessageChannel,其其Unsafe的实现类是NioMessageUnsafe,而后者继承的是AbstractNioByteChannel且其Unsafe的实现类是NioByteUnsafe,从而造成了读取逻辑相同,但是实际传输参数的不同(策略模式+多态),SocketChannel的继承结构如下图所示:
Image.png
AbstractChannel实现了Channel的大致框架,但是没有涉及具体的网络I/O,AbstractNioChannel实现了在NIO情况下的注册、连接等功能,但是I/O的读/写交给了其子类,AbstractNioByteChannel主要负责数据的读写,而AbstractNioMessageChannel主要负责连接的读写

在Server端具体的连接建立过程如下:

  1. NioServerSocketChannel的EventLoop在不断循环中通过Selector检测到有新的连接,然后调用NioMessageUnsafe.read方法

  2. 在NioMessagUnsafe.read方法中调用NioServerSocketChannel的doReadMessages方法,其中通过调用accept方法创建NIO对应的SocketChannel,并基于此创建对应的NioSocketChannel

  3. 当存在多个连接请求时,则多次调用doReadMessages方法创建多个NioSocketChannel并存入数组中,然后遍历数组针对每个NioSocketChannel,将其作为参数调用pipeline.fireChannelRead,从Head开始被InboundChannelHandler处理一直到之前在初始化NioServerSocketChannel时隐式注册的ServerBootstrapAcceptor

  4. 最终NioSocketChannel被传递到ServerBootstrapAcceptor.channelRead方法中,在该方法中将childHandler配置到NioSocketChannel的Pipeline上,同时配置对应的ChildOptions以及ChildAttributes,最终调用NioEventLoopGroup.register将新的Channel注册到worker线程组

  5. 在NioEventLoopGroup.register方法中首先调用next()方法找到下一个NioEventLoop,然后调用NioEventLoop.register方法实现真正的注册,同时由于第一次注册必然是由其他线程调用的,因此会调用eventLoop.execute方法从而初始化EventLoop绑定的线程并使其开始运行

  6. 在NioEventLoop.register方法中,通过调用unsafe.register,将底层的jdk的Channel注册到Selector上去,并且啥事件也不绑定(绑定了0),最后分别调用channelRegistered以及channelActive事件,在Head中channelActive事件会触发Channel.read方法进而从Tail一路传递到Head并调用unsafe.beginRead方法,从而向Selector注册OP_READ事件