Fork me on GitHub

Netty源码剖析四新连接接入

Netty新连接接入处理逻辑分为:检测新连接,创建NioSocketChannel,分配线程及注册selector,最后向selector注册读事件。

检测新连接

进入NioEventLoop的 processSelectedKey方法,执行read方法,进入read方法

这里会用dowhile循环,这里会调用doReadMessage方法,进入NioServerSocketChannel的doReadMessages方法

获取服务端启动过程中创建的jdk的channel,调用accept方法后拿到jdk底层java.nio.channels.socketChannel,接下来封装成NioSocketChannel,放到buf里,返回1,说明读到channel了。再进入read方法

我们做个总结就是,在服务端Channel的NioEventLoop,processSelectedKey检测到accept事件后,通过jdk的accept方法去创建jdk底层的channel包装成Netty自定义的channel,然后通过handle控制连接的速率。默认情况下读取16个连接。

创建NioSocketChannel

进入doReadMessages方法,通过new NioSocketChannel(this, ch)方法,创建Netty自己客户端的channel,并且把this(服务端的channel),ch(客户端的channel),进入NioSocketChannel的构造函数的父类,然后做了三件事情。

在进入super类

第一件事情:这里首先把channel保存,readInterestOp就是传来的读事件,然后设置此channel为非阻塞模式,

继续进入super,这里首先把parent,这个parent就是创建此客户端channel的服务端channel,也就是服务端启动过程中通过反射创建的channel,这是第二件事。我们再进入NioSocketChannel的构造方法

进入config里

继续向上

这里首先把javaSocket进行保存,接下来判断默认情况下canEnableTcpNoDelayByDefault为true,我们进入tcpNoDelay

这里通过刚刚保存的javaSocket来设置tcpNoDelay,再进入

这里就是jdk底层的java.net方法,这里设置禁止Nagle算法,创建NioSocketChannel可以分为两个部分,第一,逐层调用父类构造函数,设置该channel的阻塞方式为false,然后把对应的读事件进行保存,接下来创建一系列组件,包括id unsafe pipeline,然后第二,创建和channel相关的config,这个config就是把这个channel默认情况下设置tcpDelay为true,也就是小的数据包可以尽快的发送出去,降低延迟。

分配线程及注册selector

进入NioMessageUnsafe的read方法,while循环后开始for循环每条客户端的连接,调用pipeline的fireChannelRead方法,我们知道当服务端启动时,会初始化Channel,初始化时,pipeline会默认添加一个ServerBootstrapAcceptor,服务端Channel的pipeline的构成:(Head—>ServerBootstrapAcceptor—>Tail)

ServerBootstrapAcceptor,

channelRead主要做了三件事情1:添加childHandle,2:设置options和attrs,3:选择NioEventLoop并注册到selector

向selector注册读事件

进入AbstractChannel的register0方法

  1. Netty是在哪里检测有新连接接入的

    boss线程的第一个过程,轮询出accept事件,第二个 过程通过jdk底层的channel,acceptor方法去创建这条连接。

  2. 新连接是怎样注册到NioEventLoop线程的

    boss线程调用chooser的next方法,拿到一个NioEventLoop,然后将这条连接注册到NioEventLoop上。