文章目录
- 二:启动ServerBootstrap
- 1. 配置主从Reactor线程组
- 2.配置服务端channel
- 3.为NioServerSocketChannel配置端口
- 4.为NioServerSocketChannel配置ChannelOption
- 5. 为服务端NioServerSocketChannel中的Pipeline配置ChannelHandler
- 6. 为客户端NioSocketChannel中的Pipeline配置ChannelHandler
- 7.Netty服务端的启动
- initAndRegister
- 1.1 创建通道
- 1.2 初始化NioServerSocketChannel
- **这里为什么不干脆直接将`ChannelHandler`添加到`pipeline`中,而是又使用到了`ChannelInitializer`呢?**
- 1.3 向MainReactor注册ServerSocketChannel
- 1.3.1 主Reactor线程组中选取一个Main Reactor进行注册
- 1.3.2 向绑定后的Main Reactor进行注册
- 1.3.3 Reactor线程的启动
- 1.3.4 startThread
- 1.3.5 register0
- 1.3.6 doRegister()
- 1.3.7 HandlerAdded事件回调中初始化ChannelPipeline
- 1.3.8 回调regFuture的ChannelFutureListener
- 2. doBind0
- 3. 绑定端口地址
二:启动ServerBootstrap
ServerBootstrap
主要负责对主从Reactor线程组
相关的配置进行管理,其中带child前缀的配置方法
是对从Reactor线程组
的相关配置管理。从Reactor线程组
中的Sub Reactor
负责管理的客户端NioSocketChannel
相关配置存储在ServerBootstrap
结构中。
父类AbstractBootstrap
则是主要负责对主Reactor线程组
相关的配置进行管理,以及主Reactor线程组
中的Main Reactor
负责处理的服务端ServerSocketChannel
相关的配置管理。
1. 配置主从Reactor线程组
//(2) 创建ServerBootstrap,以引导和绑定服务器
ServerBootstrap b = new ServerBootstrap();
//设置反应堆线程组,boss用于处理连接监听事件,worker用于处理传输数据事件
b.group(boosGroup,workerGroup)
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
public B group(EventLoopGroup group) {
ObjectUtil.checkNotNull(group, "group");
if (this.group != null) {
throw new IllegalStateException("group set already");
}
this.group = group;
return self();
}
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
private volatile EventLoopGroup childGroup;//Sub Reactor线程组
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
super.group(parentGroup);//设置工作线程组和boss组
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
}
this.childGroup = ObjectUtil.checkNotNull(childGroup, "childGroup");
return this;
}
}
2.配置服务端channel
EventLoopGroup workerGroup = new NioEventLoopGroup();
b.channel(NioServerSocketChannel.class)//(3) 指定所使用的 NIO 传输 Channel
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
public B channel(Class<? extends C> channelClass) {
return channelFactory(new ReflectiveChannelFactory<C>(
ObjectUtil.checkNotNull(channelClass, "channelClass")
));
}
public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory) {
return channelFactory((ChannelFactory<C>) channelFactory);
}
public B channelFactory(ChannelFactory<? extends C> channelFactory) {
ObjectUtil.checkNotNull(channelFactory, "channelFactory");
if (this.channelFactory != null) {
throw new IllegalStateException("channelFactory set already");
}
//封装channel
this.channelFactory = channelFactory;
return self();
}
}
这里就是将channel类封装成反射工厂对象,可通过ReflectiveChannelFactory创建channel对象。在Netty服务端启动的过程中,会通过这个ChannelFactory
去创建相应的Channel
实例。
下面为ServerSocketChannel
在不同IO模型下的实现:
BIO | NIO | AIO |
---|---|---|
OioServerSocketChannel | NioServerSocketChannel | AioServerSocketChannel |
EventLoopGroup
Reactor线程组在不同IO模型下的实现:
BIO | NIO | AIO |
---|---|---|
ThreadPerChannelEventLoopGroup | NioEventLoopGroup | AioEventLoopGroup |
2.1 ReflectiveChannelFactory
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
private final Constructor<? extends T> constructor;
public ReflectiveChannelFactory(Class<? extends T> clazz) {
ObjectUtil.checkNotNull(clazz, "clazz");
try { //获取Channel构造
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
" does not have a public non-arg constructor", e);
}
}
@Override
public T newChannel() {
try {
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
@Override
public String toString() {
return StringUtil.simpleClassName(ReflectiveChannelFactory.class) +
'(' + StringUtil.simpleClassName(constructor.getDeclaringClass()) + ".class)";
}
}
可以看出该类通过泛型T加反射创建对象的,泛型T继承channel,表示通过工厂反射创建channel类型。
3.为NioServerSocketChannel配置端口
ServerBootstrap b = new ServerBootstrap();
//(4) 使用指定的端口设置套接字地址
b.localAddress(new InetSocketAddress(port))
4.为NioServerSocketChannel配置ChannelOption
ServerBootstrap b = new ServerBootstrap();
//是否开启TCP底层心跳机制,默认2小时,默认关闭
b.option(ChannelOption.SO_KEEPALIVE,true)
//设置buf分配器,默认池化buf分配器
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
//true:立即发送数据(默认true). false:将小的碎片数据连接成更大的报文来最小化所发送报文的数量(相当于开启Nagle算法)
.option(ChannelOption.TCP_NODELAY, true)
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>(); //serverSocket配置
public <T> B option(ChannelOption<T> option, T value) {
ObjectUtil.checkNotNull(option, "option");
synchronized (options) {
if (value == null) {
options.remove(option);
} else {
options.put(option, value);
}
}
return self();
}
}
这里将所有option存储map中。
由于客户端NioSocketChannel
是由从Reactor线程组
中的Sub Reactor
来负责处理,所以涉及到客户端NioSocketChannel
所有的方法和配置全部是以child
前缀开头。
ServerBootstrap b = new ServerBootstrap();
//为客户端channel设置选项
b.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();//子channel配置
public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
ObjectUtil.checkNotNull(childOption, "childOption");
synchronized (childOptions) {
if (value == null) {
childOptions.remove(childOption);
} else {
childOptions.put(childOption, value);
}
}
return this;
}
}
子channel也是存储在map中。
5. 为服务端NioServerSocketChannel中的Pipeline配置ChannelHandler
ServerBootstrap b = new ServerBootstrap();
b.handler(new ChannelHandler() {
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("add");
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("remove");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("exception");
}
})
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
//父channelhandler
private volatile ChannelHandler handler;
public B handler(ChannelHandler handler) {
this.handler = ObjectUtil.checkNotNull(handler, "handler");
return self();
}
}
向NioServerSocketChannel
中的Pipeline
添加ChannelHandler
分为两种方式:
- 显示添加,如上所示。当需要添加多个handler时,可通过ChannelInitializer向pipe添加
- 隐式添加,主reactor启动时会注册ServerBootstrapAcceptor,主要用于接收客户端请求后,初始化客户端
NioSocketChannel
,在从Reactor线程组中
选取一个Sub Reactor
,通过此handler创建NioSocketChannel,将客户端NioSocketChannel
注册到Sub Reactor
中的selector
上。
6. 为客户端NioSocketChannel中的Pipeline配置ChannelHandler
ServerBootstrap b = new ServerBootstrap();
//(5) 添加一个EchoServerHandler到于Channel的 ChannelPipeline ,配置子通道channel,也就是accept的channel
b.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
//EchoServerHandler 被标注为@Shareable,所以我们可以总是使用同样的实例
//这里对于所有的客户端连接来说,都会使用同一个 EchoServerHandler,因为其被标注为@Sharable
//ChannelInitializer执行完initChannel,会将自己删除,因为一条通道只需要初始化一次
/**
* 那为什么不直接添加ChannelHandler而是选择用ChannelInitializer呢?
* 这里主要有两点原因:
* 前边我们提到,客户端NioSocketChannel是在服务端accept连接后,在服务端NioServerSocketChannel中被创建出来的。但是此时我们正处于配置ServerBootStrap阶段,服务端还没有启动,更没有客户端连接上来,此时客户端NioSocketChannel还没有被创建出来,所以也就没办法向客户端NioSocketChannel的pipeline中添加ChannelHandler。
* 客户端NioSocketChannel中Pipeline里可以添加任意多个ChannelHandler,但是Netty框架无法预知用户到底需要添加多少个ChannelHandler,所以Netty框架提供了回调函数ChannelInitializer#initChannel,使用户可以自定义ChannelHandler的添加行为。
* 当客户端NioSocketChannel注册到对应的Sub Reactor上后,紧接着就会初始化NioSocketChannel中的Pipeline,此时Netty框架会回调ChannelInitializer#initChannel执行用户自定义的添加逻辑。
*/
ch.pipeline().addLast(echoChannelHandler);
ch.pipeline().addLast(serverHandler);//使用一个EchoServerHandler 的实例初始化每一个新的Channel
}
});
那为什么不直接添加ChannelHandler
而是选择用ChannelInitializer
呢?
这里主要有两点原因:
- 前边我们提到,客户端
NioSocketChannel
是在服务端accept连接后,在服务端NioServerSocketChannel
中被创建出来的。但是此时我们正处于配置ServerBootStrap
阶段,服务端还没有启动,更没有客户端连接上来,此时客户端NioSocketChannel
还没有被创建出来,所以也就没办法向客户端NioSocketChannel
的pipeline中添加ChannelHandler
。 - 客户端
NioSocketChannel
中Pipeline
里可以添加任意多个ChannelHandler
,但是Netty框架无法预知用户到底需要添加多少个ChannelHandler
,所以Netty框架提供了回调函数ChannelInitializer#initChannel
,使用户可以自定义ChannelHandler
的添加行为。
当客户端NioSocketChannel
注册到对应的Sub Reactor
上后,紧接着就会初始化NioSocketChannel
中的Pipeline
,此时Netty框架会回调ChannelInitializer#initChannel
执行用户自定义的添加逻辑。
通道注册完成后,会调用fireChannelRegistered,触发通道注册事件
@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
@Override
@SuppressWarnings("unchecked")
public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
// Normally this method will never be called as handlerAdded(...) should call initChannel(...) and remove
// the handler.
//将channel添加到pipe
if (initChannel(ctx)) {
// we called initChannel(...) so we need to call now pipeline.fireChannelRegistered() to ensure we not
// miss an event.
ctx.pipeline().fireChannelRegistered();
// We are done with init the Channel, removing all the state for the Channel now.
removeState(ctx);
} else {
// Called initChannel(...) before which is the expected behavior, so just forward the event.
ctx.fireChannelRegistered();
}
}
@SuppressWarnings("unchecked")
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.add(ctx)) { // Guard against re-entrance.
try {
//执行初始化handler方法,将父handler添加到pipe,以及ServerBootstrapAcceptor
initChannel((C) ctx.channel());
} catch (Throwable cause) {
// Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
// We do so to prevent multiple calls to initChannel(...).
exceptionCaught(ctx, cause);
} finally {
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
//如果包含当前handler,则删除当前handler
pipeline.remove(this);
}
}
return true;
}
return false;
}
protected abstract void initChannel(C ch) throws Exception;
}
这里调用的initChannel抽象方法就是我们实现的方法。
//(5) 添加一个EchoServerHandler到于Channel的 ChannelPipeline ,配置子通道channel,也就是accept的channel
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
//EchoServerHandler 被标注为@Shareable,所以我们可以总是使用同样的实例
//这里对于所有的客户端连接来说,都会使用同一个 EchoServerHandler,因为其被标注为@Sharable
//ChannelInitializer执行完initChannel,会将自己删除,因为一条通道只需要初始化一次
/**
* 那为什么不直接添加ChannelHandler而是选择用ChannelInitializer呢?
* 这里主要有两点原因:
* 前边我们提到,客户端NioSocketChannel是在服务端accept连接后,在服务端NioServerSocketChannel中被创建出来的。但是此时我们正处于配置ServerBootStrap阶段,
* 服务端还没有启动,更没有客户端连接上来,此时客户端NioSocketChannel还没有被创建出来,所以也就没办法向客户端NioSocketChannel的pipeline中添加ChannelHandler。
* 客户端NioSocketChannel中Pipeline里可以添加任意多个ChannelHandler,但是Netty框架无法预知用户到底需要添加多少个ChannelHandler,
* 所以Netty框架提供了回调函数ChannelInitializer#initChannel,使用户可以自定义ChannelHandler的添加行为。
* 当客户端NioSocketChannel注册到对应的Sub Reactor上后,紧接着就会初始化NioSocketChannel中的Pipeline,
* 此时Netty框架会回调ChannelInitializer#initChannel执行用户自定义的添加逻辑。
*/
ch.pipeline().addLast(echoChannelHandler);
ch.pipeline().addLast(serverHandler);//使用一个EchoServerHandler 的实例初始化每一个新的Channel
}
});
7.Netty服务端的启动
ChannelFuture f = b.bind().sync();
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
public ChannelFuture bind() {
//校验netty核心组件是否配置齐全
validate();
SocketAddress localAddress = this.localAddress;
if (localAddress == null) {
throw new IllegalStateException("localAddress not set");
}
//启动服务端,绑定端口地址,接收客户端连接
return doBind(localAddress);
}
private ChannelFuture doBind(final SocketAddress localAddress) {
//1.异步创建,初始化,注册ServerSocketChannel到main reactor上
//创建通道并注册到eventLoop,初始化pipline,并添加handler到piple,打开一个nio的ServerSocketChannel,并设置非阻塞。
//将channel注册到eventLoop的selector上,将父handler注册到pipe,以及剔除初始化的handler
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
//2.任务完成则绑定端口
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
// Registration future is almost always fulfilled already, but just in case it's not.
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
//3.如果此时注册操作没有完成,则向regFuture添加operationComplete回调函数,注册成功后回调。
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
//执行失败处理
if (cause != null) {
// Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
// IllegalStateException once we try to access the EventLoop of the Channel.
promise.setFailure(cause);
} else {
// Registration was successful, so set the correct executor to use.
// See https://github.com/netty/netty/issues/2586
//标记
promise.registered();
//socket绑定地址
doBind0(regFuture, channel, localAddress, promise);
}
}
});
return promise;
}
}
}
initAndRegister
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
//1.创建通道,打开一个nio的ServerSocketChannel,设置accept事件并设置非阻塞。初始化pipline。
channel = channelFactory.newChannel();
//2.初始化channel,设置Attributes和option
init(channel);
} catch (Throwable t) {
if (channel != null) {
// channel can be null if newChannel crashed (eg SocketException("too many open files"))
channel.unsafe().closeForcibly();
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
//3.向MainReactor注册ServerSocketChannel,
// 将channel注册到eventLoop的selector上,事件默认0,将accept和父handler注册到pipe,以及剔除初始化的handler
// 获取的是bossGroup进行注册channel
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
// If we are here and the promise is not failed, it's one of the following cases:
// 1) If we attempted registration from the event loop, the registration has been completed at this point.
// i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
// 2) If we attempted registration from the other thread, the registration request has been successfully
// added to the event loop's task queue for later execution.
// i.e. It's safe to attempt bind() or connect() now:
// because bind() or connect() will be executed *after* the scheduled registration task is executed
// because register(), bind(), and connect() are all bound to the same thread.
return regFuture;
}
该函数主要创建NioServerSocketChannel,并对此初始化,然后注册到Main Reactor
中。
1.1 创建通道
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
@Override
public T newChannel() {
try {
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
}
简单通过反射创建
//一个 io.netty.channel.socket.ServerSocketChannel 实现,它使用基于 NIO 选择器的实现来接受新连接。
public class NioServerSocketChannel extends AbstractNioMessageChannel
implements io.netty.channel.socket.ServerSocketChannel {
//SelectorProvider(用于创建Selector和Selectable Channels)
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
//ServerSocketChannel相关的配置
private final ServerSocketChannelConfig config;
public NioServerSocketChannel() {
//打开一个nio的ServerSocketChannel,并设置非阻塞,以及标记accept事件。
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>.
*/
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException(
"Failed to open a server socket.", e);
}
}
public NioServerSocketChannel(ServerSocketChannel channel) {
//设置非阻塞
super(null, channel, SelectionKey.OP_ACCEPT);
//相当于把本类和ServerSocketChannel存储配置中
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
}
这里创建了一个ServerSocketChannel,并注册OP_ACCEPT事件,创建channel的配置类,该类封装了当前对象和nio原生socket。
AbstractNioMessageChannel:对NioServerSocketChannel底层读写行为的封装和定义
AbstractNioChannel
public abstract class AbstractNioChannel extends AbstractChannel {
//JDK NIO原生Selectable Channel
private final SelectableChannel ch;
// Channel监听事件集合 这里是SelectionKey.OP_ACCEPT事件
protected final int readInterestOp;
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
//设置非阻塞
ch.configureBlocking(false);
} catch (IOException e) {
try {
ch.close();
} catch (IOException e2) {
logger.warn(
"Failed to close a partially initialized socket.", e2);
}
throw new ChannelException("Failed to enter non-blocking mode.", e);
}
}
}
这里分别做了三件事
- 封装JDK NIO原生
ServerSocketChannel
。 - 封装channel感兴趣的事件,这里为OP_ACCEPT
- 设置非阻塞,用于多路复用。
AbstractChannel
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
//channel是由创建层次的,比如ServerSocketChannel 是 SocketChannel的 parent
private final Channel parent;
//channel全局唯一ID machineId+processId+sequence+timestamp+random
private final ChannelId id;
//unsafe用于封装对底层socket的相关操作
private final Unsafe unsafe;
//为channel分配独立的pipeline用于IO事件编排
private final DefaultChannelPipeline pipeline;
protected AbstractChannel(Channel parent) {
//定义父通道,对于NioServerSocketChannel来说parent为null,NioSocketChannel为接收到该连接的服务器连接监听通道
this.parent = parent;
//channel全局唯一ID machineId+processId+sequence+timestamp+random
id = newId();
//底层nio通道,完成实际io操作
unsafe = newUnsafe();
//一条通道拥有一条流水线,将channel存储pipline
pipeline = newChannelPipeline();
}
protected ChannelId newId() {
return DefaultChannelId.newInstance();
}
}
- parent保存上一级channel,channel是由创建层次的,比如ServerSocketChannel 是 SocketChannel的 parent
- 为channel分配全局唯一ID,
ChannelId
由机器Id(machineId
),进程Id(processId
),序列号(sequence
),时间戳(timestamp
),随机数(random
)构成
public final class DefaultChannelId implements ChannelId {
public static DefaultChannelId newInstance() {
return new DefaultChannelId();
}
private DefaultChannelId() {
data = new byte[MACHINE_ID.length + PROCESS_ID_LEN + SEQUENCE_LEN + TIMESTAMP_LEN + RANDOM_LEN];
int i = 0;
// machineId
System.arraycopy(MACHINE_ID, 0, data, i, MACHINE_ID.length);
i += MACHINE_ID.length;
// processId
i = writeInt(i, PROCESS_ID);
// sequence
i = writeInt(i, nextSequence.getAndIncrement());
// timestamp (kind of)
i = writeLong(i, Long.reverse(System.nanoTime()) ^ System.currentTimeMillis());
// random
int random = PlatformDependent.threadLocalRandom().nextInt();
i = writeInt(i, random);
assert i == data.length;
hashCode = Arrays.hashCode(data);
}
}
- 创建NioServerSocketChannel的底层操作类,这里为io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe
Unsafe
为Channel接口
的一个内部接口,用于定义实现对Channel底层的各种操作,Unsafe接口
定义的操作行为只能由Netty框架的Reactor线程
调用,用户线程禁止调用。
interface Unsafe {
//分配接收数据用的Buffer
RecvByteBufAllocator.Handle recvBufAllocHandle();
//服务端绑定的端口地址
SocketAddress localAddress();
//远端地址
SocketAddress remoteAddress();
//channel向Reactor注册
void register(EventLoop eventLoop, ChannelPromise promise);
//服务端绑定端口地址
void bind(SocketAddress localAddress, ChannelPromise promise);
//客户端连接服务端
void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
//关闭channle
void close(ChannelPromise promise);
//读数据
void beginRead();
//写数据
void write(Object msg, ChannelPromise promise);
}
-
创建pipeline,主要用于编排handler。本质是个双向队列
public class DefaultChannelPipeline implements ChannelPipeline { //pipeline中的头结点 final AbstractChannelHandlerContext head; //pipeline中的尾结点 final AbstractChannelHandlerContext tail; protected DefaultChannelPipeline(Channel channel) { //pipeline中持有对应channel的引用 this.channel = ObjectUtil.checkNotNull(channel, "channel"); succeededFuture = new SucceededChannelFuture(channel, null); voidPromise = new VoidChannelPromise(channel, true); tail = new TailContext(this); head = new HeadContext(this); head.next = tail; tail.prev = head; } }
到此为止NioServerSocketChannel内容如下:
1.2 初始化NioServerSocketChannel
@Override
void init(Channel channel) {
//1.向NioServerSocketChannelConfig设置ServerSocketChannelOption
setChannelOptions(channel, newOptionsArray(), logger);
//2.向netty自定义的NioServerSocketChannel设置attributes
setAttributes(channel, newAttributesArray());
//获取pipe
ChannelPipeline p = channel.pipeline();
//获取从Reactor线程组
final EventLoopGroup currentChildGroup = childGroup;
//获取用于初始化客户端NioSocketChannel的ChannelInitializer
final ChannelHandler currentChildHandler = childHandler;
//获取用户配置的客户端SocketChannel的channelOption以及attributes
final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
//3.向NioServerSocketChannel中的pipeline添加初始化ChannelHandler的逻辑
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
//获取父handler
ChannelHandler handler = config.handler();
if (handler != null) {
//父handler添加到pipe
pipeline.addLast(handler);
}
//这里为什么不干脆直接将ChannelHandler添加到pipeline中,而是又使用到了ChannelInitializer呢?
//其实原因有两点:
//为了保证线程安全地初始化pipeline,所以初始化的动作需要由Reactor线程进行,而当前线程是用户程序的启动Main线程 并不是Reactor线程。这里不能立即初始化。
//初始化Channel中pipeline的动作,需要等到Channel注册到对应的Reactor中才可以进行初始化,当前只是创建好了NioServerSocketChannel,但并未注册到Main Reactor上。
//初始化NioServerSocketChannel中pipeline的时机是:当NioServerSocketChannel注册到Main Reactor之后,绑定端口地址之前。
//在该初始化回调方法中,添加LoggingHandler是直接向pipeline中添加,而添加Acceptor为什么不是直接添加而是封装成异步任务呢?
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {//管道添加ServerBootstrapAcceptor
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
- 向NioServerSocketChannelConfig设置ServerSocketChannelOption
- 向netty自定义的NioServerSocketChannel设置attributes
- 可以看到该channel继承AttributeMap,DefaultAttributeMap,正是它们定义了
ChannelAttributes
。用于向Channel
添加用户自定义的一些信息。
- 可以看到该channel继承AttributeMap,DefaultAttributeMap,正是它们定义了
- 获取从Reactor线程组
childGroup
,以及用于初始化客户端NioSocketChannel
的ChannelInitializer
,ChannelOption
,ChannelAttributes
,这些信息均是由用户在启动的时候向ServerBootstrap
添加的客户端NioServerChannel
配置信息。这里用这些信息来初始化ServerBootstrapAcceptor
。因为后续会在ServerBootstrapAcceptor
中接收客户端连接以及创建NioServerChannel
。 - 向
NioServerSocketChannel
中的pipeline
添加用于初始化pipeline
的ChannelInitializer
。
这里为什么不干脆直接将ChannelHandler
添加到pipeline
中,而是又使用到了ChannelInitializer
呢?
- 为了保证
线程安全
地初始化pipeline
,所以初始化的动作需要由Reactor线程
进行,而当前线程是用户程序
的启动Main线程
并不是
Reactor线程。这里不能立即初始化。 - 初始化
Channel
中pipeline
的动作,需要等到Channel
注册到对应的Reactor
中才可以进行初始化,当前只是创建好了NioServerSocketChannel
,但并未注册到Main Reactor
上。
添加Acceptor为什么不是直接添加而是封装成异步任务呢?
此时NioServerSocketChannel
中的pipeline
结构如下图所示:
1.3 向MainReactor注册ServerSocketChannel
ChannelFuture regFuture = config().group().register(channel);
从ServerBootstrap
获取主Reactor线程组NioEventLoopGroup
,将NioServerSocketChannel
注册到NioEventLoopGroup
中。
1.3.1 主Reactor线程组中选取一个Main Reactor进行注册
public ChannelFuture register(Channel channel) {
//简单的遍历EventLoop,然后将channel注册到eventLoop上
return next().register(channel);
}
@Override
public EventLoop next() {
//简单的遍历EventLoop
return (EventLoop) super.next();
}
@Override
public EventExecutor next() {
return chooser.next();
}
private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
}
从ReactorGroup
中选取一个Reactor进行注册绑定。之后Channel
生命周期内的所有IO 事件
都由这个Reactor
负责处理,如 accept、connect、read、write
等 IO 事件。
由于这里是NioServerSocketChannle
向Main Reactor
进行注册绑定,所以Main Reactor
主要负责处理的IO事件
是OP_ACCEPT
事件。
1.3.2 向绑定后的Main Reactor进行注册
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
@Override
public ChannelFuture register(Channel channel) {
//注册channel到绑定的Reactor上
return register(new DefaultChannelPromise(channel, this));
}
@Override
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
//将channel注册selector上,事件默认0,将accept和父handler注册到pipe,以及剔除初始化的handler
promise.channel().unsafe().register(this, promise);
return promise;
}
}
通过NioServerSocketChannel
中的Unsafe类
执行底层具体的注册动作。
protected abstract class AbstractUnsafe implements Unsafe {
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
ObjectUtil.checkNotNull(eventLoop, "eventLoop");
//1.检查是否已经注册
if (isRegistered()) {
promise.setFailure(new IllegalStateException("registered to an event loop already"));
return;
}
//2.EventLoop的类型要与Channel的类型一样 Nio Oio Aio
if (!isCompatible(eventLoop)) {
promise.setFailure(
new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
return;
}
//3.在channel上设置绑定的Reactor
AbstractChannel.this.eventLoop = eventLoop;
/**
* 执行channel注册的操作必须是Reactor线程来完成
*
* 1: 如果当前执行线程是Reactor线程,则直接执行register0进行注册
* 2:如果当前执行线程是外部线程,则需要将register0注册操作 封装程异步Task 由Reactor线程执行
* */
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
eventLoop.execute(new Runnable() {
@Override
public void run() {
//将channel注册selector上,事件默认0,将accept和父handler注册到pipe,以及剔除初始化的handler
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);
}
}
}
}
-
执行
Channel
向Reactor
注册的动作必须要确保是在Reactor线程
中执行。 -
- 如果当前线程是
Reactor线程
则直接执行注册动作register0
- 如果当前线程不是
Reactor线程
,则需要将注册动作register0
封装成异步任务,存放在Reactor
中的taskQueue
中,等待Reactor线程
执行。
- 如果当前线程是
当前执行线程并不是
Reactor线程
,而是用户程序的启动线程Main线程
。
1.3.3 Reactor线程的启动
接下来执行,Reactor线程
的启动是在向Reactor
提交第一个异步任务的时候启动的。
eventLoop.execute(new Runnable() {
@Override
public void run() {
//将channel注册selector上,事件默认0,将accept和父handler注册到pipe,以及剔除初始化的handler
register0(promise);
}
});
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
@Override
public void execute(Runnable task) {
ObjectUtil.checkNotNull(task, "task");
//任务是否是排队执行还是立即执行
execute(task, !(task instanceof LazyRunnable) && wakesUpForTask(task));
}
private void execute(Runnable task, boolean immediate) {
//1.当前线程是否为Reactor线程
boolean inEventLoop = inEventLoop();
//2.将任务添加到队列,如果当前实例已经关闭,则拒绝。
addTask(task);
if (!inEventLoop) {
//3.如果当前线程不是Reactor线程,则启动Reactor线程
//这里可以看出Reactor线程的启动是通过 向NioEventLoop添加异步任务时启动的
//标记线程启用,当没任务时,调用select(),等待事件连接
startThread();
if (isShutdown()) {
boolean reject = false;
try {
if (removeTask(task)) {
reject = true;
}
} catch (UnsupportedOperationException e) {
// The task queue does not support removal so the best thing we can do is to just move on and
// hope we will be able to pick-up the task before its completely terminated.
// In worst case we will log on termination.
}
if (reject) {
reject();
}
}
}
//immediate:提交的task需要立即执行
//addTaskWakesUp:true 表示当且仅当只有调用addTask方法时才会唤醒Reactor线程。调用别的方法并不会唤醒Reactor线程。
// 在初始化NioEventLoop时会设置为false,表示并不是只有addTask方法才能唤醒Reactor线程 还有其他方法可以唤醒Reactor线程,
// 比如这里的execute方法就会唤醒Reactor线程。
if (!addTaskWakesUp && immediate) {
//4.将Reactor线程从Selector上唤醒
wakeup(inEventLoop);
}
}
}
- 将任务添加到队列
- 如果当前线程不是Reactor线程,则启动Reactor线程。此时当前线程为main线程。所以这里会启动reactor线程。
1.3.4 startThread
public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
//Reactor线程状态 初始为 未启动状态
private volatile int state = ST_NOT_STARTED;
//定义Reactor线程状态
private static final int ST_NOT_STARTED = 1;
private static final int ST_STARTED = 2;
private static final int ST_SHUTTING_DOWN = 3;
private static final int ST_SHUTDOWN = 4;
private static final int ST_TERMINATED = 5;
//Reactor线程状态字段state 原子更新器
private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "state");
private void startThread() {
if (state == ST_NOT_STARTED) {
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
boolean success = false;
try {
//Reactor线程开始启动
doStartThread();
success = true;
} finally {
//启动失败回滚状态
if (!success) {
STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
}
}
}
}
}
}
Reactor线程
初始化状态为ST_NOT_STARTED
,首先CAS
更新状态为ST_STARTED
doStartThread
启动Reactor线程
- 启动失败的话,需要将
Reactor线程
状态改回ST_NOT_STARTED
private final Executor executor;
private void doStartThread() {
assert thread == null;
executor.execute(new Runnable() {
@Override
public void run() {
.....
//Reactor线程开始启动
SingleThreadEventExecutor.this.run();
.....
}
});
}
Reactor线程
的核心工作之前介绍过:轮询所有注册其上的Channel中的IO就绪事件
,处理对应Channel上的IO事件
,执行异步任务
。Netty将这些核心工作封装在io.netty.channel.nio.NioEventLoop#run
方法中。
- 将
NioEventLoop#run
封装在异步任务中,提交给executor
执行,Reactor
线程至此开始工作了就。
public final class ThreadPerTaskExecutor implements Executor {
private final ThreadFactory threadFactory;
@Override
public void execute(Runnable command) {
//启动Reactor线程
threadFactory.newThread(command).start();
}
}
此时Reactor线程
已经启动,后面的工作全部都由这个Reactor线程
来负责执行了。
而用户启动线程在向Reactor
提交完NioServerSocketChannel
的注册任务register0
后,就逐步退出调用堆栈,回退到最开始的启动入口处ChannelFuture f = b.bind(PORT).sync()
。
此时Reactor
中的任务队列中只有一个任务register0
,Reactor线程
启动后,会从任务队列中取出任务执行。
1.3.5 register0
//是否从未注册过
private boolean neverRegistered = true;
//标记是否注册
private volatile boolean registered;
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
//1.查看注册操作是否已经取消,或者通道是否仍然打开,因为它可能在注册调用在 eventLoop 之外的同时关闭
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
//如果频道从未注册过,则为 true,否则为 false
boolean firstRegistration = neverRegistered;
//2.channel注册选择器上
doRegister();
//标记注册过
neverRegistered = false;
registered = true;
// Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
// user may already fire events through the pipeline in the ChannelFutureListener.
//3.初始化channelPipeline,回调pipeline中添加的ChannelInitializer的handlerAdded方法
//主要将accept和父handler注册到pipe,以及剔除初始化的handler
pipeline.invokeHandlerAddedIfNeeded();
//4.设置regFuture为success,触发operationComplete回调,将bind操作放入Reactor的任务队列中,等待Reactor线程执行。
//会触发io.netty.channel.ChannelFutureListener#operationComplete,进行端口绑定
safeSetSuccess(promise);
//5.通道注册完成后,成功绑定NioEventLoop线程后,会调用fireChannelRegistered,触发通道注册事件
pipeline.fireChannelRegistered();
// Only fire a channelActive if the channel has never been registered. This prevents firing
// multiple channel actives if the channel is deregistered and re-registered.
//对于服务端ServerSocketChannel来说 只有绑定端口地址成功后 channel的状态才是active的。
//此时绑定操作作为异步任务在Reactor的任务队列中,绑定操作还没开始,所以这里的isActive()是false
if (isActive()) {
//6.当通道激活完成后(所有的业务处理器添加,注册的异步任务完成,并且NioEventLoop线程绑定的异步任务完成),会调用fireChannelActive,触发通道激活事件
if (firstRegistration) {
//触发channelActive事件
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
// This channel was registered before and autoRead() is set. This means we need to begin read
// again so that we process inbound data.
//
// See https://github.com/netty/netty/issues/4805
beginRead();
}
}
} catch (Throwable t) {
// Close the channel directly to avoid FD leak.
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
-
查看注册操作是否已经取消,或者通道是否仍然打开,因为它可能在注册调用在 eventLoop 之外的同时关闭
-
channel注册选择器上
-
初始化channelPipeline,回调pipeline中添加的ChannelInitializer的handlerAdded方法
-
设置regFuture为success,触发operationComplete回调,将bind操作放入Reactor的任务队列中,等待Reactor线程执行。
-
通道注册完成后,成功绑定NioEventLoop线程后,会调用fireChannelRegistered,触发通道注册事件
-
当通道激活完成后(所有的业务处理器添加,注册的异步任务完成,并且NioEventLoop线程绑定的异步任务完成),会调用fireChannelActive,触发通道激活事件
1.3.6 doRegister()
public abstract class AbstractNioChannel extends AbstractChannel {
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
//注册选择器,并将chanle封装到附件,并将selectionKey保存channel中
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;
}
}
}
}
}
调用jdk 原生选择器将channel注册上去,并将netty封装的channel作为附件。
1.3.7 HandlerAdded事件回调中初始化ChannelPipeline
当NioServerSocketChannel
注册到Main Reactor
上的Selector
后,Netty通过调用pipeline.invokeHandlerAddedIfNeeded()
开始回调NioServerSocketChannel
中pipeline
里的ChannelHandler的handlerAdded方法
。
此时NioServerSocketChannel
的pipeline
结构如下:
@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
//因为init是全局共享的,所以通过initMap来存储已经初始化的pipeline,避免重复创建
private final Set<ChannelHandlerContext> initMap = Collections.newSetFromMap(
new ConcurrentHashMap<ChannelHandlerContext, Boolean>());
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
if (initChannel(ctx)) {
removeState(ctx);
}
}
}
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.add(ctx)) { // Guard against re-entrance.
try {
//执行初始化handler方法,将父handler添加到pipe,以及ServerBootstrapAcceptor
initChannel((C) ctx.channel());
} catch (Throwable cause) {
// Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
// We do so to prevent multiple calls to initChannel(...).
exceptionCaught(ctx, cause);
} finally {
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
//如果包含当前handler,则删除当前handler
pipeline.remove(this);
}
}
return true;
}
return false;
}
protected abstract void initChannel(C ch) throws Exception;
private void removeState(final ChannelHandlerContext ctx) {
//从initMap防重Set集合中删除ChannelInitializer
if (ctx.isRemoved()) {
initMap.remove(ctx);
} else {
ctx.executor().execute(new Runnable() {
@Override
public void run() {
initMap.remove(ctx);
}
});
}
}
}
- 首先查看channel是否注册了,注册了则执行匿名类中initChannel逻辑。
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
//获取Main Reactor handler
ChannelHandler handler = config.handler();
if (handler != null) {
//MainReactor handler添加到pipe
pipeline.addLast(handler);
}
//这里为什么不干脆直接将ChannelHandler添加到pipeline中,而是又使用到了ChannelInitializer呢?
//其实原因有两点:
//为了保证线程安全地初始化pipeline,所以初始化的动作需要由Reactor线程进行,而当前线程是用户程序的启动Main线程 并不是Reactor线程。这里不能立即初始化。
//初始化Channel中pipeline的动作,需要等到Channel注册到对应的Reactor中才可以进行初始化,当前只是创建好了NioServerSocketChannel,但并未注册到Main Reactor上。
//初始化NioServerSocketChannel中pipeline的时机是:当NioServerSocketChannel注册到Main Reactor之后,绑定端口地址之前。
//在该初始化回调方法中,添加LoggingHandler是直接向pipeline中添加,而添加Acceptor为什么不是直接添加而是封装成异步任务呢?
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {//管道添加ServerBootstrapAcceptor
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
- 当执行完
initChannel 方法
后,ChannelPipeline
的初始化就结束了,此时ChannelInitializer
就没必要再继续呆在pipeline中了
,所需要将ChannelInitializer
从pipeline
中删除。pipeline.remove(this)
1.3.8 回调regFuture的ChannelFutureListener
执行initAndRegister是一个异步的过程,所以在initAndRegister()
方法调用后返回一个代表注册结果的ChannelFuture regFuture
。
private ChannelFuture doBind(final SocketAddress localAddress) {
.......
//2.任务完成则绑定端口
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
// Registration future is almost always fulfilled already, but just in case it's not.
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
//3.如果此时注册操作没有完成,则向regFuture添加operationComplete回调函数,注册成功后回调。
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
//执行失败处理
if (cause != null) {
// Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
// IllegalStateException once we try to access the EventLoop of the Channel.
promise.setFailure(cause);
} else {
// Registration was successful, so set the correct executor to use.
// See https://github.com/netty/netty/issues/2586
//标记
promise.registered();
//socket绑定地址
doBind0(regFuture, channel, localAddress, promise);
}
}
});
return promise;
}
..........
}
之后会向ChannelFuture regFuture
添加一个注册完成后的回调函数 ChannelFutureListener
。在回调函数operationComplete
中开始发起绑端口地址流程
。
那么这个回调函数在什么时候?什么地方发起的呢??
让我们在回到本小节的主题register0
方法的流程中:
当调用doRegister()
方法完成NioServerSocketChannel
向Main Reactor
的注册后,紧接着会调用pipeline.invokeHandlerAddedIfNeeded()
方法中触发ChannelInitializer#handlerAdded
回调中对pipeline
进行初始化。
最后在safeSetSuccess
方法中,开始回调注册在regFuture
上的ChannelFutureListener
。
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected final void safeSetSuccess(ChannelPromise promise) {
if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
logger.warn("Failed to mark a promise as success because it is done already: {}", promise);
}
}
}
public class DefaultChannelPromise extends DefaultPromise<Void> implements ChannelPromise, FlushCheckpoint {
@Override
public boolean trySuccess() {
return trySuccess(null);
}
@Override
public boolean trySuccess(V result) {
return setSuccess0(result);
}
private boolean setSuccess0(V result) {
return setValue0(result == null ? SUCCESS : result);
}
private boolean setValue0(Object objResult) {
if (RESULT_UPDATER.compareAndSet(this, null, objResult) ||
RESULT_UPDATER.compareAndSet(this, UNCANCELLABLE, objResult)) {
if (checkNotifyWaiters()) {
//回调注册在promise上的listeners
notifyListeners();
}
return true;
}
return false;
}
}
regFuture设置为success后然后回调所有监听器。
2. doBind0
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (regFuture.isSuccess()) {
//绑定地址,并添加channel关闭事件
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
}
这里Netty又将绑定端口地址
的操作封装成异步任务,提交给Reactor
执行。
但是这里有一个问题,其实此时执行doBind0
方法的线程正是Reactor线程
,那为什么不直接在这里去执行bind操作
,而是再次封装成异步任务提交给Reactor
中的taskQueue
呢?
反正最终都是由Reactor线程
执行,这其中又有什么分别呢?
经过上小节的介绍我们知道,bind0
方法的调用是由io.netty.channel.AbstractChannel.AbstractUnsafe#register0
方法在将NioServerSocketChannel
注册到Main Reactor
之后,并且NioServerSocketChannel
的pipeline
已经初始化完毕后,通过safeSetSuccess
方法回调过来的。
这个过程全程是由Reactor线程
来负责执行的,但是此时register0
方法并没有执行完毕,还需要执行后面的逻辑。
而绑定逻辑需要在注册逻辑执行完之后执行,所以在doBind0
方法中Reactor线程
会将绑定操作
封装成异步任务先提交给taskQueue
中保存,这样可以使Reactor线程
立马从safeSetSuccess
中返回,继续执行剩下的register0
方法逻辑。
private void register0(ChannelPromise promise) {
................省略............
doRegister();
pipeline.invokeHandlerAddedIfNeeded();
//4.设置regFuture为success,触发operationComplete回调,将bind操作放入Reactor的任务队列中,等待Reactor线程执行。
//会触发io.netty.channel.ChannelFutureListener#operationComplete,进行端口绑定
safeSetSuccess(promise);
//5.通道注册完成后,成功绑定NioEventLoop线程后,会调用fireChannelRegistered,触发通道注册事件
pipeline.fireChannelRegistered();
................省略............
}
当Reactor线程
执行完register0
方法后,就会从taskQueue
中取出异步任务执行。
-
Reactor线程
会先取出位于taskQueue
队首的任务执行,这里是指向NioServerSocketChannel
的pipeline
中添加ServerBootstrapAcceptor
的异步任务。此时
NioServerSocketChannel
中pipeline
的结构如下:
- 接着
Reactor线程
执行绑定任务。
3. 绑定端口地址
对Channel
的操作行为全部定义在ChannelOutboundInvoker接口中
。
public interface ChannelOutboundInvoker {
ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise);
ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise);
}
AbstractChannel实现bind方法
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return pipeline.bind(localAddress, promise);
}
}
调用pipeline.bind(localAddress, promise)
在pipeline
中传播bind事件
,触发回调pipeline
中所有ChannelHandler
的bind方法
。
事件在pipeline
中的传播具有方向性:
inbound事件
从HeadContext
开始逐个向后传播直到TailContext
。outbound事件
则是反向传播,从TailContext
开始反向向前传播直到HeadContext
。
inbound事件
只能被pipeline
中的ChannelInboundHandler
响应处理outbound事件
只能被pipeline
中的ChannelOutboundHandler
响应处理
然而这里的bind事件
在Netty中被定义为outbound事件
,所以它在pipeline
中是反向传播。先从TailContext
开始反向传播直到HeadContext
。然而bind
的核心逻辑也正是实现在HeadContext
中。
public class DefaultChannelPipeline implements ChannelPipeline {
@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return tail.bind(localAddress, promise);
}
}
3.1 HeadContext
final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler {
@Override
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
unsafe.bind(localAddress, promise);
}
}
调用channel的unsafe对象实现bind
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected abstract void doBind(SocketAddress localAddress) throws Exception;
protected abstract class AbstractUnsafe implements Unsafe {
@Override
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.");
}
//查看该socket是否连接,这个时候还未激活。
boolean wasActive = isActive();
try {
//绑定地址
doBind(localAddress);
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
return;
}
/* 那么为何不直接触发pipeline中的ChannelActive事件而是又封装成异步任务呢??
因为如果直接在这里触发ChannelActive事件,那么Reactor线程就会去执行pipeline中的ChannelHandler的channelActive事件回调。
这样的话就影响了safeSetSuccess(promise)的执行,延迟了注册在promise上的ChannelFutureListener的回调。*/
if (!wasActive && isActive()) {
//当通道激活完成后(所有的业务处理器添加,注册的异步任务完成,并且NioEventLoop线程绑定的异步任务完成),会调用fireChannelActive,触发通道激活事件
invokeLater(new Runnable() {
@Override
public void run() {
//注册accept事件
pipeline.fireChannelActive();
}
});
}
//回调注册在promise上的ChannelFutureListener
safeSetSuccess(promise);
}
}
}
执行NioServerSocketChannel类的doBind进行绑定
protected void doBind(SocketAddress localAddress) throws Exception {
//调用jdk原生bind方法
if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
- 判断是否为首次绑定,如果是的话将
触发pipeline中的ChannelActive事件
封装成异步任务放入Reactor
中的taskQueue
中。 - 执行
safeSetSuccess(promise)
,回调注册在promise
上的ChannelFutureListener
。
还是同样的问题,当前执行线程已经是Reactor线程
了,那么为何不直接触发pipeline
中的ChannelActive
事件而是又封装成异步任务呢??
因为如果直接在这里触发ChannelActive事件
,那么Reactor线程
就会去执行pipeline
中的ChannelHandler
的channelActive事件回调
。
这样的话就影响了safeSetSuccess(promise)
的执行,延迟了
注册在promise
上的ChannelFutureListener
的回调。
到现在为止,Netty服务端就已经完成了绑定端口地址的操作,NioServerSocketChannel
的状态现在变为Active
。
最后还有一件重要的事情要做,我们接着来看pipeline
中对channelActive事件
处理。
3.2 channelActive事件处理
Active事件在Netty中定义为inbound事件
,所以它在pipeline
中的传播为正向传播,从HeadContext
一直到TailContext
为止。
在channelActive事件
回调中需要触发向Selector
指定需要监听的IO事件
~~OP_ACCEPT事件
。
final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler {
@Override
public void channelActive(ChannelHandlerContext ctx) {
//pipeline中继续向后传播channelActive事件
//触发通道激活事件
ctx.fireChannelActive();
//如果是autoRead 则自动触发read事件传播
//在read回调函数中 触发OP_ACCEPT注册
//注册accept事件
readIfIsAutoRead();
}
private void readIfIsAutoRead() {
//如果是autoRead 则触发read事件传播,默认为true
if (channel.config().isAutoRead()) {
//selector 注册accept事件
channel.read();
}
}
}
接着触发read事件
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
@Override
public Channel read() {
pipeline.read();
return this;
}
}
read事件在Netty中定义为outbound事件
,所以它在pipeline
中的传播为正向传播,从TailContext
一直到HeadContext
为止。
final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler {
@Override
public void read(ChannelHandlerContext ctx) {
//触发注册OP_ACCEPT或者OP_READ事件
unsafe.beginRead();
}
}
- 在
HeadContext
中的channelActive
回调中触发pipeline
中的read事件
。 - 当
read事件
再次传播到HeadContext
时,触发HeadContext#read
方法的回调。在read回调
中调用channel
底层操作类unsafe
的beginRead
方法向selector
注册监听OP_ACCEPT事件
。
3.3 beginRead
protected abstract class AbstractUnsafe implements Unsafe {
@Override
public final void beginRead() {
//断言判断执行该方法的线程必须是Reactor线程。
assertEventLoop();
//channel必须是Active
if (!isActive()) {
return;
}
try {
//注册accept事件,触发在selector上注册channel感兴趣的监听事件
doBeginRead();
} catch (final Exception e) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireExceptionCaught(e);
}
});
close(voidPromise());
}
}
}
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
protected abstract void doBeginRead() throws Exception;
}
- 断言判断执行该方法的线程必须是Reactor线程。
- 判断channel是否为活跃状态,此时channel已经绑定端口了,处于活跃状态。
- 注册accept事件,触发在selector上注册channel感兴趣的监听事件
public abstract class AbstractNioChannel extends AbstractChannel {
volatile SelectionKey selectionKey;
boolean readPending;
// Channel监听事件集合 这里是SelectionKey.OP_ACCEPT事件
protected final int readInterestOp;
@Override
protected void doBeginRead() throws Exception {
// Channel.read() or ChannelHandlerContext.read() was called
final SelectionKey selectionKey = this.selectionKey;
//查看SelectionKey是否有效
if (!selectionKey.isValid()) {
return;
}
readPending = true;
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
//注册accept事件
selectionKey.interestOps(interestOps | readInterestOp);
}
}
}
- 在
NioServerSocketChannel
在向Main Reactor
中的Selector
注册后,会获得一个SelectionKey
。这里首先要获取这个SelectionKey
。 - 从
SelectionKey
中获取NioServerSocketChannel
感兴趣的IO事件集合 interestOps
,当时在注册的时候interestOps
设置为0
。 - 将在
NioServerSocketChannel
初始化时设置的readInterestOp = OP_ACCEPT
,设置到SelectionKey
中的interestOps
集合中。这样Reactor
中的Selector
就开始监听interestOps
集合中包含的IO事件
了。
此时Main Reactor
中主要监听的是OP_ACCEPT事件
。
流程图如下:
此时Netty的Reactor模型
结构如下: