目录
1 简介
1.1 线程模型
1.2 ChannelHandler & ChannelPipeline
1.3 直接内存
2 NioEventLoopGroup
3 ServerBootstrap & Bootstrap
3.1 构造器
3.2 group方法
3.3 channel方法
3.4 option方法
3.5 childHandler & handler方法
3.6 bind & connect方法
4 sync方法
5 writeAndFlush方法
6 心跳检测机制
6.1 构造器
6.2 channelActive方法
6.3 channelRead方法
Netty版本:4.1.51.Final。
因为NIO的类库和API比较繁琐,使用起来比较麻烦,开发的工作量和难度都非常大,例如客户端面临断连重连、网络闪断、心跳处理、半包读写、网络拥塞和异常流的处理等等。所以Netty对Java自带的NIO API进行了良好的封装,解决了上述问题。且Netty拥有高性能、吞吐量更高、延迟更低、减少资源消耗,零拷贝直接内存等优点。所以Netty可以很方便地实现出一个网络通信系统,比如聊天服务器或弹幕系统(我曾经使用Netty实现过一个简易聊天室的demo,感兴趣的可以查看《Netty实现简易聊天室的功能》),同时在分布式框架中,像阿里的Dubbo和RocketMQ,底层使用的就是Netty来作为基础通信组件。
需要注意的是:Netty曾经有Netty 5这个版本,但是后来被废弃掉了,现在使用的都是Netty 4的版本。之所以被废弃,最主要的原因是Netty 5中使用了ForkJoinPool,增加了代码的复杂性却没有很明显的性能提升,同时增加了没有必要的多版本分支的维护工作(Norman Maurer(《Netty IN ACTION》作者,同时他现在也在领导着Netty项目)的原话在此https://github.com/netty/netty/issues/4466)。
值得一提的是:在2016年Norman Maurer曾经对Netty做过一次演讲,详细介绍了4.x版本相对于3.x版本所做的改进之处。讲解的非常好,感兴趣的可以查看《Netty - One Framework to rule them all....》(中文字幕版)。
Netty使用的是NIO的模型(我之前写过一篇讲解BIO、NIO和AIO的文章,感兴趣的可以查看《BIO & NIO & AIO》),但是对于NIO模型来说,我当时示例代码的服务端是只用了一个线程来处理。那么假如此时有十万多个客户端需要和服务端IO交互,而其中某一个客户端和服务端的IO交互花费时间很长,剩下的十万个IO请求就都会被阻塞住。即使服务端使用的是线程池,服务端也不可能开十万个线程,多余的线程也会被放在阻塞队列中进行阻塞。所以在Netty中又进一步优化了原有NIO的模型:
上面就是Netty的线程模型图,其中客户端我没有细画是因为其执行逻辑和服务端大致都是类似的,只不过客户端只有一组线程组(WorkerGroup),而不是服务端的两组(BossGroup和WorkerGroup)。
在服务端中BossGroup只负责接收客户端的连接(一般只需要一个线程就可以了,如果需要监听多个端口才需要开多个NioEventLoop);而WorkerGroup专门负责网络的读写,是真正干活的线程,WorkerGroup做成多个NioEventLoop的话就会有多个selector来处理客户端的IO请求。Netty通过这种方式来实现对连接IO操作和读写IO操作的分离,让两者之间不会受干扰,不会出现一个读写IO非常慢从而导致后面的连接IO被阻塞的情况。同时如果连接IO出现问题的话,往往是网络出现异常;而读写IO出现问题可能是业务代码逻辑上有问题。这样就可以通过职责分离,快速定位出问题所在(分治的思想通常是实现任何可扩展性目标的最佳方法)。
每个NioEventLoop(可以把NioEventLoop理解为一个线程,而NioEventLoopGroup就相当于线程池)都会循环做三件事:
其实这里Netty的线程模型源自于Doug Lea大神写过的一篇文章《Scalable IO in Java》中的Multiple Reactors模型:
ChannelHandler是处理服务端和客户端入站(站在客户端的角度来说,服务端往客户端发送数据;或者站在服务端的角度来说,客户端往服务端发送数据叫做入站)和出站(站在客户端的角度来说,客户端往服务端发送数据;或者站在服务端的角度来说,服务端往客户端发送数据叫做出站)的逻辑容器,具体可分为ChannelInboundHandler和ChannelOutboundHandler。ChannelInboundHandler是用来处理入站逻辑的,而ChannelOutboundHandler是用来处理出站逻辑的。比方说我现在写了一个自定义编解码的逻辑,那么ChannelInboundHandler就是写解码逻辑的,而ChannelOutboundHandler是写编码逻辑的。当然Netty中也内置了一些ChannelHandler,比如说对String的编解码逻辑StringEncoder和StringDecoder,对象的编解码逻辑ObjectEncoder和ObjectDecoder等。
如上面的Netty线程模型图所示,在处理实际业务时用到的就是ChannelHandler。但是上面的图画的只是一个大概,完整的服务端和客户端ChannelHandler的交互示意图如下所示:
如果有多个ChannelHandler,那么它们之间是通过ChannelPipeline的方式来组合使用的,也就是说通过pipeline可以将所有的ChannelInboundHandler和ChannelOutboundHandler组合成一个处理链,但是并不是一次会把所有的ChannelHandler都执行。如上图所示:在入站的时候,只会从pipeline的head向tail方向执行处理链上所有的ChannelInboundHandler,遇到ChannelOutboundHandler的时候会跳过;而在出站的时候,只会从pipeline的tail向head方向执行处理链上所有的ChannelOutboundHandler,遇到ChannelInboundHandler的时候会跳过。
有一点需要注意的是:在一条处理链中所有出站的handler,它们之间的顺序不是随便写的。比如说我现在有一个发送数据的handler和一个编码的handler。因为出站的顺序是从pipeline的tail到head,所以发送数据的handler一定要放在编码handler的后面,也就是必须要先发送数据再编码。如果这个顺序反了,就变成了先编码再发送数据,那么就不会发送成功数据,逻辑就有问题了。同时对于所有入站的handler也是一样的道理。因为入站的顺序是从pipeline的head到tail,所以接收数据的handler也是一定要放在解码handler的后面,也就是必须要先解码再接收数据。
直接内存是相对于堆内存来说的,它并不是JVM运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。某些情况下直接内存也会被频繁地使用,而且也有可能会导致OOM的出现。元空间对应的内存可以叫作直接内存,同时在NIO编程中用DirectByteBuffer也可以分配一块直接内存,它们对应的都是机器的物理内存。
但是在NIO编程中直接内存的API非常难用,稍不留意就会写出bug。所以在Netty中已经帮我们封装为了ByteBuf类,使用起来更加方便。ByteBuf的大致数据结构如下:
每调用一次writeByte方法,writerIndex指针就+1;每调用一次readByte方法,readerIndex指针就+1;而getByte方法是不会造成指针移动的。所以就可以依据这两个指针划分为三个区间:
值得一提的是:直接内存虽然执行速度更快,但是其创建和销毁是很耗时间的(起码比堆内存慢)。所以在Netty中,对ByteBuf使用了内存池的缓冲区重用机制,提前放进去了一些ByteBuf。
在上面的Netty线程模型图中,bossGroup和workerGroup就是NioEventLoopGroup,也就是Netty自己封装的线程池。
/**
* NioEventLoopGroup:
* 无参构造器
*/
public NioEventLoopGroup() {
//这里nThreads会赋值为0
this(0);
}
/**
* 有参构造器
*/
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null);
}
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
public NioEventLoopGroup(
int nThreads, Executor executor, final SelectorProvider selectorProvider) {
this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}
public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}
/**
* MultithreadEventLoopGroup:
*/
protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
/*
从这里可以看到,如果是无参构造器,传进来的nThreads就是0,那么就会为DEFAULT_EVENT_LOOP_THREADS
而DEFAULT_EVENT_LOOP_THREADS值的初始化过程在下面,默认为当前JVM最大可用线程数*2
*/
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
//...
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
/*
如果用户没有设置“io.netty.eventLoopThreads”和“io.netty.availableProcessors”这两个参数,
DEFAULT_EVENT_LOOP_THREADS的值就默认为当前JVM最大可用线程数*2(至少要为1)
*/
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
if (logger.isDebugEnabled()) {
logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
}
}
//...
}
/**
* MultithreadEventExecutorGroup:
* 第39行代码处:
*/
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}
/*
不管是有参构造器还是无参构造器,传进来的executor都是null,所以在此进行初始化的工作,
赋值为一个Netty封装过的executor
*/
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//EventExecutor也是Netty封装过的线程池接口,这里的children就相当于一个线程池
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i++) {
boolean success = false;
try {
/*
这里默认会调用NioEventLoopGroup的newChild方法从而new出一个NioEventLoop,相当于一个Netty封装过的线程
(实际上是相当于线程池,只不过这个线程池里只会有一个线程)。现在再来看一下之前的Netty线程模型图:children就
相当于bossGroup或workerGroup,而其中的每一个元素就是NioEventLoop
*/
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
Thread.currentThread().interrupt();
break;
}
}
}
}
}
//这里会调用DefaultEventExecutorChooserFactory的newChooser方法
chooser = chooserFactory.newChooser(children);
final FutureListener
Bootstrap在Netty中是启动的辅助类,可以在其中加上一些配置项。具体可分为服务端的ServerBootstrap和客户端的Bootstrap。
/**
* ServerBootstrap:
*/
public ServerBootstrap() {
//这里虽然是空实现,但在ServerBootstrap类中会完成如下所示的初始化工作
}
public class ServerBootstrap extends AbstractBootstrap {
//...
private final Map, Object> childOptions = new LinkedHashMap, Object>();
private final Map, Object> childAttrs = new ConcurrentHashMap, Object>();
private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);
//...
}
/**
* ServerBootstrapConfig:
* 第13行代码处:
*/
ServerBootstrapConfig(ServerBootstrap bootstrap) {
super(bootstrap);
}
/**
* AbstractBootstrapConfig:
*/
protected AbstractBootstrapConfig(B bootstrap) {
//这里会将ServerBootstrap赋值给this.bootstrap
this.bootstrap = ObjectUtil.checkNotNull(bootstrap, "bootstrap");
}
/**
* Bootstrap:
*/
public Bootstrap() {
//这里虽然是空实现,但在Bootstrap类中会完成如下所示的初始化工作
}
public class Bootstrap extends AbstractBootstrap {
//...
private final BootstrapConfig config = new BootstrapConfig(this);
//...
}
/**
* BootstrapConfig:
* 第44行代码处:
*/
BootstrapConfig(Bootstrap bootstrap) {
//这里会一样调用AbstractBootstrapConfig的构造器,将Bootstrap赋值给AbstractBootstrapConfig.bootstrap
super(bootstrap);
}
/**
* ServerBootstrap:
* ServerBootstrap中的bossGroup会赋值给AbstractBootstrap的group;
* 而workerGroup会赋值给ServerBootstrap的childGroup
*/
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
//会调用到AbstractBootstrap的group方法
super.group(parentGroup);
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
}
this.childGroup = ObjectUtil.checkNotNull(childGroup, "childGroup");
return this;
}
/**
* AbstractBootstrap:
* 第8行代码处、以及Bootstrap调用group方法处:
* Bootstrap中的workerGroup会赋值给AbstractBootstrap的group
*/
public B group(EventLoopGroup group) {
ObjectUtil.checkNotNull(group, "group");
if (this.group != null) {
throw new IllegalStateException("group set already");
}
this.group = group;
return self();
}
@SuppressWarnings("unchecked")
private B self() {
return (B) this;
}
/**
* AbstractBootstrap:
*/
public B channel(Class channelClass) {
//这里传进来的是NioServerSocketChannel(服务端)或NioSocketChannel(客户端)
return channelFactory(new ReflectiveChannelFactory(
ObjectUtil.checkNotNull(channelClass, "channelClass")
));
}
/**
* ReflectiveChannelFactory:
*/
public ReflectiveChannelFactory(Class clazz) {
ObjectUtil.checkNotNull(clazz, "clazz");
try {
/*
把NioServerSocketChannel或NioSocketChannel的空参数构造器赋值进constructor,
后续会通过反射的方式进行调用
*/
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
" does not have a public non-arg constructor", e);
}
}
/**
* AbstractBootstrap:
* 第6行代码处:
*/
public B channelFactory(io.netty.channel.ChannelFactory channelFactory) {
return channelFactory((io.netty.bootstrap.ChannelFactory) channelFactory);
}
@Deprecated
public B channelFactory(io.netty.bootstrap.ChannelFactory channelFactory) {
ObjectUtil.checkNotNull(channelFactory, "channelFactory");
if (this.channelFactory != null) {
throw new IllegalStateException("channelFactory set already");
}
//把ReflectiveChannelFactory赋值给channelFactory
this.channelFactory = channelFactory;
return self();
}
/**
* AbstractBootstrap:
*/
public B option(ChannelOption option, T value) {
ObjectUtil.checkNotNull(option, "option");
//options是一个LinkedHashMap,里面存放着存进来的TCP定制化参数
synchronized (options) {
if (value == null) {
options.remove(option);
} else {
options.put(option, value);
}
}
return self();
}
/**
* ServerBootstrap:
*/
public ServerBootstrap childHandler(ChannelHandler childHandler) {
/*
这里就是把传进来的ChannelInitializer赋值给childHandler,而我们在其中实现的initChannel方法
会在channel被注册时回调,ChannelInitializer实例会在initChannel方法执行完毕后被销毁
后续会看到这一点
*/
this.childHandler = ObjectUtil.checkNotNull(childHandler, "childHandler");
return this;
}
/**
* AbstractBootstrap:
*/
public B handler(ChannelHandler handler) {
/*
这里就是把传进来的ChannelInitializer赋值给handler,而我们在其中实现的initChannel方法
会在channel被注册时回调,ChannelInitializer实例会在initChannel方法执行完毕后被销毁
后续会看到这一点
*/
this.handler = ObjectUtil.checkNotNull(handler, "handler");
return self();
}
bind方法看起来就是一个绑定端口的方法,实则完成服务端启动的全过程,流程不仅长而且还很复杂。而前面这些方法都只是在做一些配置而已。
而connect方法是客户端连接服务端的方法,其执行过程和bind方法大致类似,所以这里只挑出实现不一样的地方来进行分析。
/**
* AbstractBootstrap:
* 这里是服务端的bind方法
*/
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) {
//完成channel的初始化和注册过程
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
if (regFuture.isDone()) {
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@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;
}
}
/**
* Bootstrap:
* 这里是客户端的connect方法
*/
public ChannelFuture connect(String inetHost, int inetPort) {
return connect(InetSocketAddress.createUnresolved(inetHost, inetPort));
}
public ChannelFuture connect(SocketAddress remoteAddress) {
ObjectUtil.checkNotNull(remoteAddress, "remoteAddress");
validate();
return doResolveAndConnect(remoteAddress, config.localAddress());
}
private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
//完成channel的初始化和注册过程
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.isDone()) {
if (!regFuture.isSuccess()) {
return regFuture;
}
return doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise());
} else {
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
if (cause != null) {
promise.setFailure(cause);
} else {
promise.registered();
doResolveAndConnect0(channel, remoteAddress, localAddress, promise);
}
}
});
return promise;
}
}
/**
* 第16行和第61行代码处:
* 可以看到服务端和客户端都调用了initAndRegister方法,那么下面就来看一下其实现
*/
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
//这里会调用到我们之前在channel方法中创建的ReflectiveChannelFactory的newChannel方法
channel = channelFactory.newChannel();
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);
}
//这里的group方法拿到的就是bossGroup 这里也就是在对channel进行注册
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
/**
* ReflectiveChannelFactory:
* 第95行代码处:
*/
@Override
public T newChannel() {
try {
/*
之前constructor指向的是NioServerSocketChannel(服务端)或NioSocketChannel(客户端),
所以在这里调用了其空参数构造器
*/
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
/**
* NioServerSocketChannel:
* 第129行代码处:
*/
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
/**
* 这里可以看到通过newSocket方法来生成了一个ServerSocketChannel。而本方法的返回值
* ServerSocketChannel不就是NIO的ServerSocketChannel吗?所以这里就可以看出
* NioServerSocketChannel就是对原生NIO的ServerSocketChannel的包装
*/
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException(
"Failed to open a server socket.", e);
}
}
/**
* 第140行代码处:
*/
public NioServerSocketChannel(ServerSocketChannel channel) {
//这里的OP_ACCEPT正是在之前NIO编程中,对ServerSocketChannel注册OP_ACCEPT事件的相关代码
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
/**
* AbstractNioMessageChannel:
* 第162行代码处:
*/
protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent, ch, readInterestOp);
}
/**
* NioSocketChannel:
* 第129行代码处:
* 这里先不去查看AbstractNioMessageChannel的super方法,先来看一下客户端的NioSocketChannel的无参构造器
*/
public NioSocketChannel() {
this(DEFAULT_SELECTOR_PROVIDER);
}
public NioSocketChannel(SelectorProvider provider) {
this(newSocket(provider));
}
/**
* 这里跟NioServerSocketChannel一样,NioSocketChannel就是对原生
* NIO的SocketChannel的包装
*/
private static SocketChannel newSocket(SelectorProvider provider) {
try {
return provider.openSocketChannel();
} catch (IOException e) {
throw new ChannelException("Failed to open a socket.", e);
}
}
/**
* 第184行代码处:
*/
public NioSocketChannel(SocketChannel socket) {
this(null, socket);
}
public NioSocketChannel(Channel parent, SocketChannel socket) {
super(parent, socket);
config = new NioSocketChannelConfig(this, socket.socket());
}
/**
* AbstractNioByteChannel:
* 第207行代码处:
*/
protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {
/*
同服务端,这里跟NIO编程一样,对SocketChannel注册OP_READ事件,
同时也调用了AbstractNioMessageChannel的super方法
*/
super(parent, ch, SelectionKey.OP_READ);
}
/**
* AbstractNioChannel:
* 第171行和第220行代码处:
* NioServerSocketChannel和NioSocketChannel都会调用到此处
*/
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
//把注册事件赋值给readInterestOp
this.readInterestOp = readInterestOp;
try {
//下面这行代码在NIO编程也是一样的,将ServerSocketChannel或SocketChannel配置为非阻塞模式
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);
}
}
/**
* AbstractChannel:
* 第229行代码处:
*/
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
/*
这里就可以看到对pipeline进行了初始化操作。也就是说,每一个NioServerSocketChannel
或NioSocketChannel都会带有一个pipeline
*/
pipeline = newChannelPipeline();
}
protected DefaultChannelPipeline newChannelPipeline() {
return new DefaultChannelPipeline(this);
}
/**
* DefaultChannelPipeline:
*/
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
/*
这里可以看到初始化了pipeline中的head和tail的handler(HeadContext和TailContext本身就是
一个ChannelHandler),而之后如果要加ChannelHandler的话,会在tail之前加入
*/
tail = new TailContext(this);
head = new HeadContext(this);
//head和tail指针互相指向
head.next = tail;
tail.prev = head;
}
/**
* ServerBootstrap:
* 第96行代码处:
*/
@Override
void init(Channel channel) {
setChannelOptions(channel, newOptionsArray(), logger);
setAttributes(channel, attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
//拿到之前在newChannelPipeline方法里面设置好的pipeline
ChannelPipeline p = channel.pipeline();
//拿到之前在group方法里面设置好的workerGroup
final EventLoopGroup currentChildGroup = childGroup;
//拿到之前在childHandler方法里面设置好的childHandler
final ChannelHandler currentChildHandler = childHandler;
final Map.Entry, Object>[] currentChildOptions;
//我在之前没有演示,但是如果调用childOption方法,这里获取的就是childOptions
synchronized (childOptions) {
currentChildOptions = childOptions.entrySet().toArray(EMPTY_OPTION_ARRAY);
}
//我在之前没有演示,但是如果调用childAttr方法,这里获取的就是childAttrs
final Map.Entry, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY);
p.addLast(new ChannelInitializer() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
/**
* Bootstrap:
* 第96行代码处:
* (这里是客户端和服务端不一样的地方)
*/
@Override
@SuppressWarnings("unchecked")
void init(Channel channel) {
ChannelPipeline p = channel.pipeline();
p.addLast(config.handler());
setChannelOptions(channel, newOptionsArray(), logger);
setAttributes(channel, attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
}
/**
* DefaultChannelPipeline:
* 第311行和第340行代码处:
* 可以看到服务端和客户端都调用了addLast方法,那么下面就来看一下其实现(以服务端来举例)
*/
@Override
public final ChannelPipeline addLast(ChannelHandler... handlers) {
return addLast(null, handlers);
}
@Override
public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
ObjectUtil.checkNotNull(handlers, "handlers");
for (ChannelHandler h : handlers) {
if (h == null) {
break;
}
addLast(executor, null, h);
}
return this;
}
/**
* 第364行代码处:
*/
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
//把传进来的ChannelInitializer(服务端)封装为一个ChannelHandlerContext
newCtx = newContext(group, filterName(name, handler), handler);
addLast0(newCtx);
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
/**
* 第380行代码处:
*/
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}
/**
* DefaultChannelHandlerContext:
*/
DefaultChannelHandlerContext(
DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
super(pipeline, executor, name, handler.getClass());
//这里就会将服务端的ChannelInitializer赋值进handler中,后面会用到
this.handler = handler;
}
/**
* 第382行代码处:
* 从本方法就可以看出:新添加的ChannelHandlerContext会放在tail之前
*/
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
/**
* ServerBootstrap:
* 第106行代码处:
*/
@Override
public final ServerBootstrapConfig config() {
/*
这里直接返回了config,而config的赋值在一开始创建ServerBootstrap时就已经创建好了,
之前在分析ServerBootstrap的构造器中已经分析了这一点
*/
return config;
}
/**
* Bootstrap:
* 第106行代码处:
* (这里是客户端和服务端不一样的地方)
*/
@Override
public final BootstrapConfig config() {
/*
这里直接返回了config,而config的赋值在一开始创建Bootstrap时就已经创建好了,
之前在分析Bootstrap的构造器中已经分析了这一点
*/
return config;
}
/**
* AbstractBootstrapConfig:
* 第106行代码处:
*/
@SuppressWarnings("deprecation")
public final EventLoopGroup group() {
//这里返回的就是ServerBootstrap或Bootstrap中的group方法
return bootstrap.group();
}
/**
* AbstractBootstrap:
*/
@Deprecated
public final EventLoopGroup group() {
/*
这里面的group就是之前在group方法中赋值的group,即bossGroup(服务端)
或者是workerGroup(客户端)
*/
return group;
}
/**
* MultithreadEventLoopGroup:
* 第106行代码处:
*/
@Override
public ChannelFuture register(Channel channel) {
/*
每调用一次本方法,就会用EventLoopGroup的下一个EventLoop来进行注册
如果看过下面我对“next().register(channel)”这行代码的分析后就可以明白:
这里实际上只会有一个线程来执行pipeline上的所有handler的事件,期间不会
进行线程的切换,避免了锁竞争。这里也就是Netty中无锁串行化的体现
*/
return next().register(channel);
}
@Override
public EventLoop next() {
return (EventLoop) super.next();
}
/**
* MultithreadEventExecutorGroup:
*/
@Override
public EventExecutor next() {
/*
在之前NioEventLoopGroup的构造器中,会根据executors的长度是否是2的幂来选择调用
PowerOfTwoEventExecutorChooser或GenericEventExecutorChooser,也就是这里
的chooser。此处会调用其next方法
*/
return chooser.next();
}
/**
* PowerOfTwoEventExecutorChooser(DefaultEventExecutorChooserFactory):
*/
@Override
public EventExecutor next() {
/*
executors也就是之前在NioEventLoopGroup的构造器中赋值进去的children。这里就是在拿取
executors数组中的下一个EventExecutor。因为其长度为2的幂,所以可以用按位与的优化写法
来同样达到取余的效果(在HashMap和ConcurrentHashMap中也出现了同样的取余优化写法)
*/
return executors[idx.getAndIncrement() & executors.length - 1];
}
/**
* GenericEventExecutorChooser(DefaultEventExecutorChooserFactory):
*/
@Override
public EventExecutor next() {
/*
同上面的解释,这里就是当executors的长度不是2的幂的时候,使用常规的“%”取余符号来进行拿取下一个
EventExecutor的方式。之所以这里会取绝对值是为了防止出现数据溢出的情况:当idx递增到一个特别大
的数:2147483647,那么此时再+1就变成了-2147483648,就变成了一个负数。而数组的索引位置
是不可能出现负数的(如果为负数就会抛出数组索引越界异常),所以在这里会做一次取绝对值的操作
*/
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
/**
* SingleThreadEventLoop:
* 第490行代码处:
*/
@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;
}
/**
* AbstractChannel:
*/
@Override
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;
}
//将SingleThreadEventLoop赋值给AbstractChannel.eventLoop
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);
}
}
}
/**
* AbstractEventExecutor:
* 第573行代码处:
*/
@Override
public boolean inEventLoop() {
return inEventLoop(Thread.currentThread());
}
/**
* SingleThreadEventExecutor:
*/
@Override
public boolean inEventLoop(Thread thread) {
/*
这里可以看到inEventLoop方法就是用来判断当前线程和SingleThreadEventExecutor中的线程是否是同一个
而this.thread在此处还没有被赋值,为null,所以本方法返回false
*/
return thread == this.thread;
}
/**
* SingleThreadEventExecutor:
* 第577行代码处:
* 这里把register0方法的执行逻辑先放一放,先来看一下任务是如何被执行的
*/
@Override
public void execute(Runnable task) {
ObjectUtil.checkNotNull(task, "task");
execute(task, !(task instanceof LazyRunnable) && wakesUpForTask(task));
}
private void execute(Runnable task, boolean immediate) {
//同上,inEventLoop方法此时返回false
boolean inEventLoop = inEventLoop();
addTask(task);
if (!inEventLoop) {
startThread();
if (isShutdown()) {
boolean reject = false;
try {
if (removeTask(task)) {
reject = true;
}
} catch (UnsupportedOperationException e) {
}
if (reject) {
reject();
}
}
}
if (!addTaskWakesUp && immediate) {
wakeup(inEventLoop);
}
}
/**
* 第629行代码处:
*/
protected void addTask(Runnable task) {
ObjectUtil.checkNotNull(task, "task");
if (!offerTask(task)) {
reject(task);
}
}
/**
* 第656行代码处:
*/
final boolean offerTask(Runnable task) {
if (isShutdown()) {
reject();
}
//该处可以看到是把这个任务放到了任务队列(阻塞队列)中,在默认情况下容量为int的最大值。后续会执行它
return taskQueue.offer(task);
}
/**
* SingleThreadEventExecutor:
* 第631行代码处:
*/
private void startThread() {
if (state == ST_NOT_STARTED) {
//CAS操作确保每一个NioEventLoop只会启动一个线程
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
boolean success = false;
try {
doStartThread();
success = true;
} finally {
if (!success) {
STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
}
}
}
}
}
/**
* 第682行代码处:
*/
private void doStartThread() {
assert thread == null;
executor.execute(new Runnable() {
@Override
public void run() {
//这里将this.thread赋值为当前线程,之后再调用inEventLoop方法就返回为true了
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
for (; ; ) {
int oldState = state;
if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
break;
}
}
if (success && gracefulShutdownStartTime == 0) {
if (logger.isErrorEnabled()) {
logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
"be called before run() implementation terminates.");
}
}
try {
for (; ; ) {
if (confirmShutdown()) {
break;
}
}
for (; ; ) {
int oldState = state;
if (oldState >= ST_SHUTDOWN || STATE_UPDATER.compareAndSet(
SingleThreadEventExecutor.this, oldState, ST_SHUTDOWN)) {
break;
}
}
confirmShutdown();
} finally {
try {
cleanup();
} finally {
FastThreadLocal.removeAll();
STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
threadLock.countDown();
int numUserTasks = drainTasks();
if (numUserTasks > 0 && logger.isWarnEnabled()) {
logger.warn("An event executor terminated with " +
"non-empty task queue (" + numUserTasks + ')');
}
terminationFuture.setSuccess(null);
}
}
}
}
});
}
/**
* NioEventLoop:
* 第710行代码处:
* (注:以下的代码应该算是Netty中比较核心的代码了。但可惜的是,该代码的可读性非常差,嵌套了
* 大量的try-catch和if-else。我查阅了该处代码的初始几次提交者是Trustin Lee(Netty原作者)
* 和Norman Maurer,那个时候的run方法就已经嵌套了很多的if-else了-_-我能想到这里需要考虑
* 很多复杂的场景,但是应该会有一种更好的实现方式)
*/
@Override
protected void run() {
int selectCnt = 0;
//这里的死循环也就是在Netty线程模型图中,NioEventLoop画圈循环执行的含义
for (; ; ) {
try {
int strategy;
try {
strategy = selectStrategy.calculateStrategy(selectNowSupplier, hasTasks());
//下面的代码就可以理解为在NIO编程中处理各种事件的代码
switch (strategy) {
case SelectStrategy.CONTINUE:
continue;
case SelectStrategy.BUSY_WAIT:
case SelectStrategy.SELECT:
long curDeadlineNanos = nextScheduledTaskDeadlineNanos();
if (curDeadlineNanos == -1L) {
curDeadlineNanos = NONE;
}
nextWakeupNanos.set(curDeadlineNanos);
try {
if (!hasTasks()) {
strategy = select(curDeadlineNanos);
}
} finally {
nextWakeupNanos.lazySet(AWAKE);
}
default:
}
} catch (IOException e) {
rebuildSelector0();
selectCnt = 0;
handleLoopException(e);
continue;
}
selectCnt++;
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
boolean ranTasks;
if (ioRatio == 100) {
try {
if (strategy > 0) {
processSelectedKeys();
}
} finally {
ranTasks = runAllTasks();
}
} else if (strategy > 0) {
final long ioStartTime = System.nanoTime();
try {
processSelectedKeys();
} finally {
final long ioTime = System.nanoTime() - ioStartTime;
ranTasks = runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
} else {
ranTasks = runAllTasks(0);
}
if (ranTasks || strategy > 0) {
if (selectCnt > MIN_PREMATURE_SELECTOR_RETURNS && logger.isDebugEnabled()) {
logger.debug("Selector.select() returned prematurely {} times in a row for Selector {}.",
selectCnt - 1, selector);
}
selectCnt = 0;
} else if (unexpectedSelectorWakeup(selectCnt)) {
selectCnt = 0;
}
} catch (CancelledKeyException e) {
if (logger.isDebugEnabled()) {
logger.debug(CancelledKeyException.class.getSimpleName() + " raised by a Selector {} - JDK bug?",
selector, e);
}
} catch (Throwable t) {
handleLoopException(t);
}
try {
if (isShuttingDown()) {
closeAll();
if (confirmShutdown()) {
return;
}
}
} catch (Throwable t) {
handleLoopException(t);
}
}
}
/**
* 第800行代码处:
* 这里也就是在Netty线程模型图中NioEventLoop循环所做的第一件事:select
*/
private int select(long deadlineNanos) throws IOException {
if (deadlineNanos == NONE) {
/*
可以看到这里就是在调用NIO编程中的select方法,如果没有客户端来的时候,本方法会一直阻塞在这里
(从这里又可以再一次看出:Netty就是对NIO的一种复杂封装,但是使用起来会很简单)
*/
return selector.select();
}
long timeoutMillis = deadlineToDelayNanos(deadlineNanos + 995000L) / 1000000L;
//这里会调用NIO编程中有时间限制的select方法
return timeoutMillis <= 0 ? selector.selectNow() : selector.select(timeoutMillis);
}
/**
* 第822行和第830行代码处:
* 这里也就是在Netty线程模型图中NioEventLoop循环所做的第二件事:processSelectedKeys
* 跟NIO编程一样,如果有事件来临的时候,会把该事件放在selectedKeys集合中,也就会执行本方法
* 如果没有事件来临,该方法不会被调用
* (注:我建议processSelectedKey方法放在最后再看、等服务端走完所有的流程后再看比较好
* 现在可以先过掉这个方法,直接去看第三件事:runAllTasks方法的实现。因为processSelectedKey
* 方法本身就是服务端初始化完成后,客户端发起事件时才会调用的方法。如果现在就看下面的分析的话,
* 可能有些东西会不理解(我下面对processSelectedKeys方法的分析也是建立在看完了服务端所有初始化
* 流程后的基础上,再进行分析的))
*/
private void processSelectedKeys() {
/*
在之前NioEventLoopGroup的构造器中,已经对selectedKeys进行了初始化,所以这里会走
processSelectedKeysOptimized方法中
*/
if (selectedKeys != null) {
processSelectedKeysOptimized();
} else {
processSelectedKeysPlain(selector.selectedKeys());
}
}
/**
* 第903行代码处:
*/
private void processSelectedKeysOptimized() {
for (int i = 0; i < selectedKeys.size; ++i) {
//处理集合中的每一个selectedKey
final SelectionKey k = selectedKeys.keys[i];
selectedKeys.keys[i] = null;
final Object a = k.attachment();
if (a instanceof AbstractNioChannel) {
processSelectedKey(k, (AbstractNioChannel) a);
} else {
@SuppressWarnings("unchecked")
NioTask task = (NioTask) a;
processSelectedKey(k, task);
}
if (needsToSelectAgain) {
selectedKeys.reset(i + 1);
selectAgain();
i = -1;
}
}
}
/**
* 第921行代码处:
*/
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) {
unsafe.close(unsafe.voidPromise());
}
return;
}
try {
int readyOps = k.readyOps();
//处理OP_CONNECT事件
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
unsafe.finishConnect();
}
//处理OP_WRITE事件
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
ch.unsafe().forceFlush();
}
//处理OP_READ或OP_ACCEPT事件
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
/*
这里来着重研究一下read方法(OP_ACCEPT事件是客户端连接服务端传来的事件,
而OP_READ表示服务端和客户端收到彼此传来的读事件)
*/
unsafe.read();
}
} catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise());
}
}
/**
* AbstractNioMessageChannel:
* 第977行代码处:
* 假设当前是客户端连接服务端传来的OP_ACCEPT事件
*/
@Override
public void read() {
assert eventLoop().inEventLoop();
final ChannelConfig config = config();
/*
重点:这里获取到的pipeline是NioServerSocketChannel的pipeline,
也就是在之前第323行和第1682行代码处,往这个pipeline中添加了ServerBootstrapAcceptor
*/
final ChannelPipeline pipeline = pipeline();
final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
allocHandle.reset(config);
boolean closed = false;
Throwable exception = null;
try {
try {
do {
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;
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 {
if (!readPending && !config.isAutoRead()) {
removeReadOp();
}
}
}
/**
* NioServerSocketChannel:
* 第1006行代码处:
*/
@Override
protected int doReadMessages(List buf) throws Exception {
SocketChannel ch = SocketUtils.accept(javaChannel());
try {
if (ch != null) {
/*
把当前客户端的NioSocketChannel加入到readBuf中(之前分析过,NioSocketChannel
构造器中会把OP_READ事件赋值进去,并且配置为非阻塞)
*/
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;
}
/**
* SocketUtils:
* 第1055行代码处:
*/
public static SocketChannel accept(final ServerSocketChannel serverSocketChannel) throws IOException {
try {
return AccessController.doPrivileged(new PrivilegedExceptionAction() {
@Override
public SocketChannel run() throws IOException {
/*
这里也就是在NIO编程中,ServerSocketChannel调用accept方法
调用完之后,客户端的channel就已经连接起来了
*/
return serverSocketChannel.accept();
}
});
} catch (PrivilegedActionException e) {
throw (IOException) e.getCause();
}
}
/**
* DefaultChannelPipeline:
* 第1024行代码处:
*/
@Override
public final ChannelPipeline fireChannelRead(Object msg) {
AbstractChannelHandlerContext.invokeChannelRead(head, msg);
return this;
}
/**
* AbstractChannelHandlerContext:
*/
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
EventExecutor executor = next.executor();
//同上,inEventLoop方法会返回true
if (executor.inEventLoop()) {
next.invokeChannelRead(m);
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRead(m);
}
});
}
}
/**
* 第1118行代码处:
*/
private void invokeChannelRead(Object msg) {
if (invokeHandler()) {
try {
//这里也就是在执行每一个inboundHandler的read事件(以下以HeadContext为例来看一下执行过程)
((ChannelInboundHandler) handler()).channelRead(this, msg);
} catch (Throwable t) {
invokeExceptionCaught(t);
}
} else {
fireChannelRead(msg);
}
}
/**
* DefaultChannelPipeline:
* 第1136行代码处:
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
//可以看到HeadContext的channelRead事件没有做什么事,只是调用了下一个handler的channelRead事件
ctx.fireChannelRead(msg);
}
/**
* AbstractChannelHandlerContext:
*/
@Override
public ChannelHandlerContext fireChannelRead(final Object msg) {
/*
如上面对pipeline的解释,这里拿到的下一个inboundHandler其实是之前添加的ServerBootstrapAcceptor,
所以接下来就来看一下它的channelRead的实现
*/
invokeChannelRead(findContextInbound(MASK_CHANNEL_READ), msg);
return this;
}
/**
* ServerBootstrap:
*/
@Override
@SuppressWarnings("unchecked")
public void channelRead(ChannelHandlerContext ctx, Object msg) {
//这里传进来的msg就是上面第1063行代码处赋值进去的NioSocketChannel
final Channel child = (Channel) msg;
/*
addLast方法之前已经分析过了,这里也就是把我们在服务端自定义的childHandler
放到了NioSocketChannel的pipeline中
*/
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
setAttributes(child, childAttrs);
try {
/*
这里的register方法非常重要(之前已经分析过该方法的实现了),这里的作用也就是注册
NioSocketChannel到workerGroup的selector上,同时开启一个线程在select方法处被阻塞,
后续客户端的读写事件都会交由workerGroup来进行处理。也就是在Netty线程模型图中,
bossGroup和workerGroup中间连接的那条线的含义
同时,在之前register方法的分析中,我们知道它最终会回调我们自定义childHandler中的
ChannelInitializer中的的initChannel方法:也就是将我们自己写的所有handler都放到
workerGroup的pipeline中
*/
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);
}
}
/**
* AbstractNioByteChannel:
* 第977行代码处:
* 当执行完AbstractNioMessageChannel的read方法后,也就是客户端和服务端成功连接上了之后,
* 这个时候如果客户端有事件来临的时候,就会触发OP_READ事件,也就是会调用本方法
*/
@Override
public final void read() {
final ChannelConfig config = config();
if (shouldBreakReadReady(config)) {
clearReadPending();
return;
}
//同上面的解释,这个时候拿到的pipeline就是workerGroup的pipeline,也就是里面装载着我们自己写的handler
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);
//byteBuf此时就存着客户端写过来的数据
allocHandle.lastBytesRead(doReadBytes(byteBuf));
if (allocHandle.lastBytesRead() <= 0) {
byteBuf.release();
byteBuf = null;
close = allocHandle.lastBytesRead() < 0;
if (close) {
readPending = false;
}
break;
}
allocHandle.incMessagesRead(1);
readPending = false;
/*
此时就会拿着客户端写过来的数据在服务端我们自定义的handler中,遍历地去执行channelRead方法
至此整个流程就打通了
*/
pipeline.fireChannelRead(byteBuf);
byteBuf = null;
} while (allocHandle.continueReading());
allocHandle.readComplete();
//fireChannelRead方法执行完毕后,会遍历去执行channelReadComplete方法
pipeline.fireChannelReadComplete();
if (close) {
closeOnRead(pipeline);
}
} catch (Throwable t) {
handleReadException(pipeline, byteBuf, t, close, allocHandle);
} finally {
if (!readPending && !config.isAutoRead()) {
removeReadOp();
}
}
}
/**
* SingleThreadEventExecutor:
* 第825行代码处:
* 这里也就是在Netty线程模型图中NioEventLoop循环所做的第三件事:runAllTasks,也就是执行taskQueue中的任务
*/
protected boolean runAllTasks() {
assert inEventLoop();
boolean fetchedAll;
boolean ranAtLeastOne = false;
//do-while循环确保执行完所有taskQueue中的任务
do {
fetchedAll = fetchFromScheduledTaskQueue();
//执行taskQueue中的所有任务
if (runAllTasksFrom(taskQueue)) {
ranAtLeastOne = true;
}
} while (!fetchedAll);
if (ranAtLeastOne) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
}
//钩子方法,空实现
afterRunningAllTasks();
return ranAtLeastOne;
}
/**
* SingleThreadEventExecutor:
* 第833行和第836行代码处:
* 这里也就是在Netty线程模型图中NioEventLoop循环所做的第三件事:runAllTasks,也就是执行taskQueue中的任务
* (本方法是上面方法的重载方法,需要考虑定时任务超时的问题)
* (注:这两个方法为什么不考虑封装成一个公有的抽象,然后使用类似模板方法模式来进行不同的实现?)
*/
protected boolean runAllTasks(long timeoutNanos) {
fetchFromScheduledTaskQueue();
Runnable task = pollTask();
if (task == null) {
//钩子方法,空实现
afterRunningAllTasks();
return false;
}
final long deadline = timeoutNanos > 0 ? ScheduledFutureTask.nanoTime() + timeoutNanos : 0;
long runTasks = 0;
long lastExecutionTime;
for (; ; ) {
safeExecute(task);
runTasks++;
//每执行64个任务后获取一下当前时间,看是否已经超时了(因为nanoTime的获取也会有消耗,所以不是一个任务一次调用)
if ((runTasks & 0x3F) == 0) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
if (lastExecutionTime >= deadline) {
break;
}
}
task = pollTask();
if (task == null) {
lastExecutionTime = ScheduledFutureTask.nanoTime();
break;
}
}
//钩子方法,空实现
afterRunningAllTasks();
this.lastExecutionTime = lastExecutionTime;
return true;
}
/**
* 第1285行和第1308行代码处:
* 这里需要说一下前提:除了taskQueue之外还有一个scheduledTaskQueue的定时任务队列。当taskQueue存满了的时候,
* 会将剩下的任务存放进scheduledTaskQueue中。所以本方法的执行,达到的效果就是取出scheduledTaskQueue中的
* 任务再放回到taskQueue,直到taskQueue再次存满为止
*/
private boolean fetchFromScheduledTaskQueue() {
//如果scheduledTaskQueue本身就是空的,就直接返回true
if (scheduledTaskQueue == null || scheduledTaskQueue.isEmpty()) {
return true;
}
long nanoTime = AbstractScheduledEventExecutor.nanoTime();
for (; ; ) {
//从scheduledTaskQueue中拿走队头任务
Runnable scheduledTask = pollScheduledTask(nanoTime);
//如果scheduledTask是空的,说明scheduledTaskQueue中已经没有了任务(或者超时了),就直接返回true
if (scheduledTask == null) {
return true;
}
if (!taskQueue.offer(scheduledTask)) {
/*
将从scheduledTaskQueue中拿出的任务再次放到taskQueue中,循环这一过程。如果taskQueue满了放不下的话,
就把这一次拿出的任务再次放回到scheduledTaskQueue中,并返回false
*/
scheduledTaskQueue.add((ScheduledFutureTask) scheduledTask);
return false;
}
}
}
/**
* AbstractScheduledEventExecutor:
* 第1359行代码处:
* 从scheduledTaskQueue中拿走队头任务
*/
protected final Runnable pollScheduledTask(long nanoTime) {
assert inEventLoop();
ScheduledFutureTask scheduledTask = peekScheduledTask();
if (scheduledTask == null || scheduledTask.deadlineNanos() - nanoTime > 0) {
return null;
}
//如果peek获取的任务不为空或者没超时,就删除掉它,相当于拿走队头任务了
scheduledTaskQueue.remove();
scheduledTask.setConsumed();
return scheduledTask;
}
/**
* 第1383行代码处:
*/
final ScheduledFutureTask peekScheduledTask() {
Queue> scheduledTaskQueue = this.scheduledTaskQueue;
//从scheduledTaskQueue中获取队头任务
return scheduledTaskQueue != null ? scheduledTaskQueue.peek() : null;
}
/**
* SingleThreadEventExecutor:
* 第1287行代码处:
*/
protected final boolean runAllTasksFrom(Queue taskQueue) {
//拿取taskQueue中的一个任务
Runnable task = pollTaskFrom(taskQueue);
//如果任务为null,就直接返回false,说明此时taskQueue中已经没有任务了,也就不需要执行了
if (task == null) {
return false;
}
for (; ; ) {
//执行任务
safeExecute(task);
//执行完一个任务后继续拿取taskQueue中的下一个任务去执行,死循环确保重复这一过程
task = pollTaskFrom(taskQueue);
//如果任务为null,就直接返回true,说明此时taskQueue中已经没有任务了
if (task == null) {
return true;
}
}
}
/**
* 第1309行和第1332行代码处:
*/
protected Runnable pollTask() {
assert inEventLoop();
return pollTaskFrom(taskQueue);
}
/**
* 第1408行、第1417行和第1430行代码处:
*/
protected static Runnable pollTaskFrom(Queue taskQueue) {
for (; ; ) {
//拿走taskQueue中的队头任务,如果为空任务就继续拿取下一个,直到不为空为止
Runnable task = taskQueue.poll();
if (task != WAKEUP_TASK) {
return task;
}
}
}
/**
* AbstractEventExecutor:
* 第1320行和第1415行代码处:
*/
protected static void safeExecute(Runnable task) {
try {
/*
这里也就是在真正执行任务的地方。现在已经搞清楚了任务是如何启动去执行的,而之前在register注册的时候
放入了一个注册任务,那么下面就来看一下这个任务具体的执行代码
*/
task.run();
} catch (Throwable t) {
logger.warn("A task raised an exception. Task: {}", task, t);
}
}
/**
* AbstractChannel:
* 第580行代码处:
*/
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
doRegister();
neverRegistered = false;
registered = true;
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
pipeline.fireChannelRegistered();
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
} catch (Throwable t) {
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
/**
* AbstractNioChannel:
* 第1472行代码处:
*/
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (; ; ) {
try {
//这行话其实就对应于NIO编程中把ServerSocketChannel或SocketChannel注册到selector上
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
eventLoop().selectNow();
selected = true;
} else {
throw e;
}
}
}
}
/**
* DefaultChannelPipeline:
* 第1476行代码处:
*/
final void invokeHandlerAddedIfNeeded() {
assert channel.eventLoop().inEventLoop();
if (firstRegistration) {
firstRegistration = false;
//之前说过,当channel被注册时会回调initChannel方法,所以这里就是在做这件事
callHandlerAddedForAllHandlers();
}
}
private void callHandlerAddedForAllHandlers() {
final PendingHandlerCallback pendingHandlerCallbackHead;
synchronized (this) {
assert !registered;
registered = true;
pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
this.pendingHandlerCallbackHead = null;
}
PendingHandlerCallback task = pendingHandlerCallbackHead;
while (task != null) {
task.execute();
task = task.next;
}
}
/**
* 第1543行代码处:
*/
@Override
void execute() {
EventExecutor executor = ctx.executor();
//inEventLoop方法在之前第702行代码处的doStartThread方法里面已经对thread赋值成当前线程了,所以这里肯定返回true
if (executor.inEventLoop()) {
callHandlerAdded0(ctx);
} else {
try {
executor.execute(this);
} catch (RejectedExecutionException e) {
if (logger.isWarnEnabled()) {
logger.warn(
"Can't invoke handlerAdded() as the EventExecutor {} rejected it, removing handler {}.",
executor, ctx.name(), e);
}
atomicRemoveFromHandlerList(ctx);
ctx.setRemoved();
}
}
}
/**
* 第1556行代码处:
*/
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
ctx.callHandlerAdded();
} catch (Throwable t) {
boolean removed = false;
try {
atomicRemoveFromHandlerList(ctx);
ctx.callHandlerRemoved();
removed = true;
} catch (Throwable t2) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to remove a handler: " + ctx.name(), t2);
}
}
if (removed) {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() +
".handlerAdded() has thrown an exception; removed.", t));
} else {
fireExceptionCaught(new ChannelPipelineException(
ctx.handler().getClass().getName() +
".handlerAdded() has thrown an exception; also failed to remove.", t));
}
}
}
/**
* AbstractChannelHandlerContext:
* 第1577行代码处:
*/
final void callHandlerAdded() throws Exception {
if (setAddComplete()) {
/*
这里获取的handler正是之前第414行代码处,调用DefaultChannelHandlerContext构造器
赋值进去的ChannelInitializer
*/
handler().handlerAdded(this);
}
}
/**
* ChannelInitializer:
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) {
if (initChannel(ctx)) {
removeState(ctx);
}
}
}
/**
* 第1622行代码处:
*/
@SuppressWarnings("unchecked")
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.add(ctx)) {
try {
//这里就是回调之前在第313行代码处的initChannel方法,下面就来看一下该方法的实现过程
initChannel((C) ctx.channel());
} catch (Throwable cause) {
exceptionCaught(ctx, cause);
} finally {
ChannelPipeline pipeline = ctx.pipeline();
//这里就可以看到当执行完initChannel方法后会删除当前ChannelInitializer实例
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
}
return true;
}
return false;
}
/**
* ServerBootstrap:
* 第313行代码处:
* 为了延续一路分析下来的顺序,这里将之前initChannel回调方法的具体代码重新拷贝了一份放在下面,
* 以此来连贯分析其具体执行过程
*/
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
//因为我们之前调用ServerBootstrap和Bootstrap的构造器都是空实现,所以这里获取到的handler也是null
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
/*
这里又调用了一次execute方法,将任务放到taskQueue中,然后等待runAllTasks方法去执行
之前在第621行代码处已经分析了其具体执行过程,这里就不再次重复分析了
*/
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
/*
addLast方法在之前的第352行代码处也已经分析过了,将ChannelHandler添加进pipeline中
只不过之前添加的是ChannelInitializer,而这里添加的是ServerBootstrapAcceptor
(添加之后ChannelInitializer的initChannel方法就走完了,然后在上面的第1644行代码处
可以看到,会从pipeline中删除当前ChannelInitializer实例,所以目前服务端的pipeline
中除了tail和head之外,就只剩下了ServerBootstrapAcceptor(需要注意的是:添加
ServerBootstrapAcceptor是在另一个线程中完成的,主线程不一定能及时感知到这个变化))
*/
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
/*
目前这条线就算是走完了,再来回到最开始的地方,即第1476行代码处.我们刚才所有的分析都是从
invokeHandlerAddedIfNeeded方法里面进行展开的,现在该方法走完了,就继续走接下来的代码
*/
}
/**
* DefaultChannelPipeline:
* 第1479行代码处:
* 该方法实现的就是通过遍历pipeline中的每一个inboundHandler,执行其channelRegistered方法
*/
@Override
public final ChannelPipeline fireChannelRegistered() {
AbstractChannelHandlerContext.invokeChannelRegistered(head);
return this;
}
/**
* AbstractChannelHandlerContext:
*/
static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
EventExecutor executor = next.executor();
//同上,inEventLoop方法会返回true
if (executor.inEventLoop()) {
next.invokeChannelRegistered();
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelRegistered();
}
});
}
}
/**
* 第1710行代码处:
*/
private void invokeChannelRegistered() {
//该方法返回true
if (invokeHandler()) {
try {
((ChannelInboundHandler) handler()).channelRegistered(this);
} catch (Throwable t) {
invokeExceptionCaught(t);
}
} else {
fireChannelRegistered();
}
}
/**
* DefaultChannelPipeline:
* 第1728行代码处:
* 因为传进来的是head,所以这里调用的是HeadContext的channelRegistered方法
*/
@Override
public void channelRegistered(ChannelHandlerContext ctx) {
/*
invokeHandlerAddedIfNeeded方法之前已经分析过了,但是这里并不会具体执行后续的
callHandlerAddedForAllHandlers,因为在之前的调用过程中已经把firstRegistration
置为false了,详见第1524行代码处。所以这里不会再调用了,相当于是个空方法
*/
invokeHandlerAddedIfNeeded();
/*
这里是调用下一个inboundHandler的channelRegistered方法。如果是TailContext的话,就会去执行
它的channelRegistered方法。但是TailContext的channelRegistered方法是一个空实现,所以这里
就不再具体展开分析了,调用的流程都是和HeadContext类似的
*/
ctx.fireChannelRegistered();
}
/**
* AbstractChannelHandlerContext:
* 第1755行代码处:
*/
@Override
public ChannelHandlerContext fireChannelRegistered() {
/*
因为这里是调用channelRegistered事件,站在服务端的角度来说相当于入站事件
所以当通过findContextInbound方法拿到下一个inboundHandler时候,就调用
它的channelRegistered方法
*/
invokeChannelRegistered(findContextInbound(MASK_CHANNEL_REGISTERED));
return this;
}
/**
* 该方法就是用来找到下一个执行注册动作的inboundHandler
*/
private AbstractChannelHandlerContext findContextInbound(int mask) {
AbstractChannelHandlerContext ctx = this;
EventExecutor currentExecutor = executor();
do {
ctx = ctx.next;
} while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_INBOUND));
return ctx;
}
/**
* 如果返回true,则代表当前handler是需要跳过的。比如当前需要剔除outBoundHandler,那么传进来的
* onlyMask就是MASK_ONLY_INBOUND,当遇到一个outBoundHandler的时候,本方法就会返回true;
* 当遇到一个inboundHandler的时候,本方法就会返回false
*/
private static boolean skipContext(
AbstractChannelHandlerContext ctx, EventExecutor currentExecutor, int mask, int onlyMask) {
return (ctx.executionMask & (onlyMask | mask)) == 0 ||
(ctx.executor() == currentExecutor && (ctx.executionMask & mask) == 0);
}
/**
* AbstractBootstrap:
* 第14行代码处:
* 上面所有的分析都是在分析initAndRegister这个方法,现在我们来接着分析在这之后的代码,
* 首先是服务端的doBind方法。为了延续一路分析下来的顺序,这里将之前doBind方法的具体代码
* 重新拷贝了一份放在下面,以此来连贯分析其具体执行过程
*/
private ChannelFuture doBind(final SocketAddress localAddress) {
//之前已经分析了initAndRegister方法的具体执行过程
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
//该方法会返回false
if (regFuture.isDone()) {
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@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;
}
}
/**
* AbstractBootstrap:
*/
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
//之前已经分析过了,看到“eventLoop().execute”这行代码就知道是创建了一个新任务放到了taskQueue中
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());
}
}
});
}
/**
* AbstractChannel:
* 第1848行代码处:
*/
@Override
public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
/*
其实这里和channelRegistered事件的执行过程是类似的,都是遍历handler去执行事件,
但是这里是从tail到head的顺序找出outboundHandler
*/
return pipeline.bind(localAddress, promise);
}
/**
* DefaultChannelPipeline:
*/
@Override
public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
return tail.bind(localAddress, promise);
}
/**
* AbstractChannelHandlerContext:
*/
@Override
public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
ObjectUtil.checkNotNull(localAddress, "localAddress");
if (isNotValidPromise(promise, false)) {
return promise;
}
//这里就是在找下一个执行绑定动作的outboundHandler
final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND);
EventExecutor executor = next.executor();
//同之前的分析,该方法会返回true
if (executor.inEventLoop()) {
next.invokeBind(localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeBind(localAddress, promise);
}
}, promise, null, false);
}
return promise;
}
/**
* 第1888行代码处:
* 该方法的代码和findContextInbound方法代码之间的区别除了onlyMask不同之外,还有一点就是
* findContextInbound方法中是从head到tail依次遍历的;而findContextOutbound方法也就是
* 本方法中是从tail到head依次遍历的
*/
private AbstractChannelHandlerContext findContextOutbound(int mask) {
AbstractChannelHandlerContext ctx = this;
EventExecutor currentExecutor = executor();
do {
ctx = ctx.prev;
} while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_OUTBOUND));
return ctx;
}
/**
* 第1892行代码处:
*/
private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
if (invokeHandler()) {
try {
//这里也就是在执行每一个outboundHandler的bind事件(以下以HeadContext为例来看一下执行过程)
((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
} else {
bind(localAddress, promise);
}
}
/**
* DefaultChannelPipeline:
* 第1926行代码处:
*/
@Override
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) {
unsafe.bind(localAddress, promise);
}
/**
* AbstractChannel:
*/
@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
assertEventLoop();
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) &&
localAddress instanceof InetSocketAddress &&
!((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() &&
!PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) {
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() {
//这里看到会从pipeline中依次执行channelActive事件
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
/**
* NioServerSocketChannel:
* 第1968行代码处:
*/
@SuppressJava6Requirement(reason = "Usage guarded by java version check")
@Override
protected void doBind(SocketAddress localAddress) throws Exception {
/*
这里会根据Java不同的版本来执行不同的绑定代码。而看到“javaChannel()”就知道这里会走到NIO编程中的代码里了,
也就是NIO编程中的绑定端口的代码
*/
if (PlatformDependent.javaVersion() >= 7) {
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
/**
* AbstractChannel:
* 第1976行代码处:
* 该方法就是把任务放到taskQueue中
*/
private void invokeLater(Runnable task) {
try {
eventLoop().execute(task);
} catch (RejectedExecutionException e) {
logger.warn("Can't invoke task later as EventLoop rejected it", e);
}
}
/**
* DefaultChannelPipeline:
* 第1980行代码处:
*/
@Override
public final ChannelPipeline fireChannelActive() {
//这里和channelRegistered事件的执行过程是类似的,从pipeline中head到tail执行所有的inboundHandler
AbstractChannelHandlerContext.invokeChannelActive(head);
return this;
}
/**
* AbstractChannelHandlerContext:
*/
static void invokeChannelActive(final AbstractChannelHandlerContext next) {
EventExecutor executor = next.executor();
//同之前的分析,该方法会返回true
if (executor.inEventLoop()) {
next.invokeChannelActive();
} else {
executor.execute(new Runnable() {
@Override
public void run() {
next.invokeChannelActive();
}
});
}
}
/**
* 第2037行代码处:
*/
private void invokeChannelActive() {
if (invokeHandler()) {
try {
//这里也就是在执行每一个inboundHandler的active事件(以下以HeadContext为例来看一下执行过程)
((ChannelInboundHandler) handler()).channelActive(this);
} catch (Throwable t) {
invokeExceptionCaught(t);
}
} else {
fireChannelActive();
}
}
/**
* DefaultChannelPipeline:
* 第2055行代码处:
* 因为传进来的是head,所以这里调用的是HeadContext的channelActive方法
*/
@Override
public void channelActive(ChannelHandlerContext ctx) {
/*
这里是调用下一个inboundHandler的channelActive方法。如果是TailContext的话,就会去执行
它的channelActive方法。但是TailContext的channelActive方法是一个空实现,所以这里
就不再具体展开分析了,调用的流程都是和HeadContext类似的
*/
ctx.fireChannelActive();
readIfIsAutoRead();
}
/**
* AbstractChannelHandlerContext:
* 第2076行代码处:
*/
@Override
public ChannelHandlerContext fireChannelActive() {
/*
因为这里是调用channelActive事件,站在服务端的角度来说相当于入站事件
所以当通过findContextInbound方法拿到下一个inboundHandler时候,就调用
它的channelActive方法
*/
invokeChannelActive(findContextInbound(MASK_CHANNEL_ACTIVE));
return this;
}
/**
* AbstractNioChannel:
* 第2078行代码处:
* readIfIsAutoRead方法中又会从pipeline中从tail到head遍历执行所有outboundHandler的读事件,
* 之前已经分析过很多这样的流程了,这里就不再赘述了。所以下面就来看一下其中的关键代码:doBeginRead
*/
@Override
protected void doBeginRead() throws Exception {
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
readPending = true;
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
/*
这里可以看到跟NIO编程中一样,重新注册对OP_ACCEPT(服务端)或OP_READ(客户端)事件感兴趣
(详见之前的第162行和第220行代码处)
*/
selectionKey.interestOps(interestOps | readInterestOp);
}
}
/**
* Bootstrap:
* 第59行代码处:
* 分析完服务端的doBind方法后,现在来分析一下客户端的doResolveAndConnect方法
*/
private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
//之前已经分析了initAndRegister方法的具体执行过程
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.isDone()) {
if (!regFuture.isSuccess()) {
return regFuture;
}
return doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise());
} else {
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
if (cause != null) {
promise.setFailure(cause);
} else {
promise.registered();
doResolveAndConnect0(channel, remoteAddress, localAddress, promise);
}
}
});
return promise;
}
}
private ChannelFuture doResolveAndConnect0(final Channel channel, SocketAddress remoteAddress,
final SocketAddress localAddress, final ChannelPromise promise) {
try {
final EventLoop eventLoop = channel.eventLoop();
AddressResolver resolver;
try {
resolver = this.resolver.getResolver(eventLoop);
} catch (Throwable cause) {
channel.close();
return promise.setFailure(cause);
}
if (!resolver.isSupported(remoteAddress) || resolver.isResolved(remoteAddress)) {
doConnect(remoteAddress, localAddress, promise);
return promise;
}
final Future resolveFuture = resolver.resolve(remoteAddress);
if (resolveFuture.isDone()) {
final Throwable resolveFailureCause = resolveFuture.cause();
if (resolveFailureCause != null) {
channel.close();
promise.setFailure(resolveFailureCause);
} else {
doConnect(resolveFuture.getNow(), localAddress, promise);
}
return promise;
}
resolveFuture.addListener(new FutureListener() {
@Override
public void operationComplete(Future future) throws Exception {
if (future.cause() != null) {
channel.close();
promise.setFailure(future.cause());
} else {
doConnect(future.getNow(), localAddress, promise);
}
}
});
} catch (Throwable cause) {
promise.tryFailure(cause);
}
return promise;
}
/**
* 第2180行代码处:
*/
private static void doConnect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise connectPromise) {
final Channel channel = connectPromise.channel();
//同上,新创建了一个任务放到了taskQueue中
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (localAddress == null) {
channel.connect(remoteAddress, connectPromise);
} else {
channel.connect(remoteAddress, localAddress, connectPromise);
}
connectPromise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
});
}
/**
* AbstractChannel:
* 第2214行代码处:
*/
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return pipeline.connect(remoteAddress, promise);
}
/**
* DefaultChannelPipeline:
*/
@Override
public final ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
/*
不出意外的话,又是从pipeline中从tail到head遍历执行所有outboundHandler的connect事件
(注:既然有这么多pipeline中inbound、outbound的遍历执行的地方,为什么不抽象成两个公有的实现?
通过传入不同的事件来实现不同的功能?)
*/
return tail.connect(remoteAddress, promise);
}
/**
* AbstractChannelHandlerContext:
*/
@Override
public ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) {
return connect(remoteAddress, null, promise);
}
@Override
public ChannelFuture connect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
ObjectUtil.checkNotNull(remoteAddress, "remoteAddress");
if (isNotValidPromise(promise, false)) {
return promise;
}
//这里就是在找下一个执行连接动作的outboundHandler
final AbstractChannelHandlerContext next = findContextOutbound(MASK_CONNECT);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeConnect(remoteAddress, localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeConnect(remoteAddress, localAddress, promise);
}
}, promise, null, false);
}
return promise;
}
/**
* 第2266行代码处:
*/
private void invokeConnect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
if (invokeHandler()) {
try {
//这里也就是在执行每一个outboundHandler的connect事件(以下以HeadContext为例来看一下执行过程)
((ChannelOutboundHandler) handler()).connect(this, remoteAddress, localAddress, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
} else {
connect(remoteAddress, localAddress, promise);
}
}
/**
* DefaultChannelPipeline:
* 第2285行代码处:
*/
@Override
public void connect(
ChannelHandlerContext ctx,
SocketAddress remoteAddress, SocketAddress localAddress,
ChannelPromise promise) {
unsafe.connect(remoteAddress, localAddress, promise);
}
/**
* AbstractChannel:
*/
@Override
public final void connect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
try {
if (connectPromise != null) {
throw new ConnectionPendingException();
}
boolean wasActive = isActive();
if (doConnect(remoteAddress, localAddress)) {
fulfillConnectPromise(promise, wasActive);
} else {
connectPromise = promise;
requestedRemoteAddress = remoteAddress;
int connectTimeoutMillis = config().getConnectTimeoutMillis();
if (connectTimeoutMillis > 0) {
//这里schedule方法会创建一个定时任务,之前遇到的都是execute方法,所以这里来具体看一下其是怎么实现的
connectTimeoutFuture = eventLoop().schedule(new Runnable() {
@Override
public void run() {
ChannelPromise connectPromise = AbstractNioChannel.this.connectPromise;
ConnectTimeoutException cause =
new ConnectTimeoutException("connection timed out: " + remoteAddress);
if (connectPromise != null && connectPromise.tryFailure(cause)) {
close(voidPromise());
}
}
}, connectTimeoutMillis, TimeUnit.MILLISECONDS);
}
promise.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isCancelled()) {
if (connectTimeoutFuture != null) {
connectTimeoutFuture.cancel(false);
}
connectPromise = null;
close(voidPromise());
}
}
});
}
} catch (Throwable t) {
promise.tryFailure(annotateConnectException(t, remoteAddress));
closeIfClosed();
}
}
/**
* NioSocketChannel:
* 第2322行代码处:
*/
@Override
protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
if (localAddress != null) {
doBind0(localAddress);
}
boolean success = false;
try {
boolean connected = SocketUtils.connect(javaChannel(), remoteAddress);
if (!connected) {
//同NIO编程中一样,为该通道注册OP_CONNECT事件
selectionKey().interestOps(SelectionKey.OP_CONNECT);
}
success = true;
return connected;
} finally {
if (!success) {
doClose();
}
}
}
/**
* SocketUtils:
* 第2375行代码处:
*/
public static boolean connect(final SocketChannel socketChannel, final SocketAddress remoteAddress)
throws IOException {
try {
return AccessController.doPrivileged(new PrivilegedExceptionAction() {
@Override
public Boolean run() throws IOException {
//这里也就是在NIO编程中,客户端连接服务端的代码
return socketChannel.connect(remoteAddress);
}
});
} catch (PrivilegedActionException e) {
throw (IOException) e.getCause();
}
}
/**
* AbstractScheduledEventExecutor:
* 第2331行代码处:
*/
@Override
public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) {
ObjectUtil.checkNotNull(command, "command");
ObjectUtil.checkNotNull(unit, "unit");
//delay非负处理
if (delay < 0) {
delay = 0;
}
validateScheduled0(delay, unit);
return schedule(new ScheduledFutureTask(
this,
command,
deadlineNanos(unit.toNanos(delay))));
}
private ScheduledFuture schedule(final ScheduledFutureTask task) {
//同之前的分析,该方法会返回true
if (inEventLoop()) {
scheduleFromEventLoop(task);
} else {
final long deadlineNanos = task.deadlineNanos();
if (beforeScheduledTaskSubmitted(deadlineNanos)) {
execute(task);
} else {
lazyExecute(task);
if (afterScheduledTaskSubmitted(deadlineNanos)) {
execute(WAKEUP_TASK);
}
}
}
return task;
}
/**
* 第2431行代码处:
*/
final void scheduleFromEventLoop(final ScheduledFutureTask task) {
//这里实际上就是将任务放在了定时任务队列中,后续再去等线程执行runAllTasks方法,把任务拿出来再执行
scheduledTaskQueue().add(task.setId(++nextTaskId));
}
PriorityQueue> scheduledTaskQueue() {
if (scheduledTaskQueue == null) {
scheduledTaskQueue = new DefaultPriorityQueue>(
SCHEDULED_FUTURE_TASK_COMPARATOR,
11);
}
return scheduledTaskQueue;
}
@SuppressWarnings("unchecked")
public DefaultPriorityQueue(Comparator comparator, int initialSize) {
this.comparator = ObjectUtil.checkNotNull(comparator, "comparator");
//这里可以看到创建了一个Netty自己定义的优先级队列(继承了java.util.AbstractQueue)
queue = (T[]) (initialSize != 0 ? new PriorityQueueNode[initialSize] : EMPTY_ARRAY);
}
在执行完上述的所有过程后,运行NioEventLoop类run方法的线程,在没有遇到事件来临的时候,会阻塞在select方法处,直到有事件来临(这和NIO编程中的执行逻辑是一样的)。
/**
* DefaultChannelPromise:
*/
@Override
public ChannelPromise sync() throws InterruptedException {
super.sync();
return this;
}
/**
* DefaultPromise:
*/
@Override
public Promise sync() throws InterruptedException {
await();
rethrowIfFailed();
return this;
}
/**
* DefaultChannelPromise:
* 第15行代码处:
*/
@Override
public ChannelPromise await() throws InterruptedException {
super.await();
return this;
}
/**
* DefaultPromise:
*/
@Override
public Promise await() throws InterruptedException {
if (isDone()) {
return this;
}
if (Thread.interrupted()) {
throw new InterruptedException(toString());
}
checkDeadLock();
synchronized (this) {
while (!isDone()) {
incWaiters();
try {
/*
这里就是会让当前线程阻塞住,直到上一个异步操作执行完毕后再被唤醒,也就是“异步转同步”
比如“bind(9000).sync()”这行代码就是在等待初始化注册和绑定端口工作都做完了以后,当前线程再被唤醒;
而“closeFuture().sync()”这行代码就是在等待通道关闭、处理完毕后,当前线程再被唤醒
*/
wait();
} finally {
decWaiters();
}
}
}
return this;
}
/**
* AbstractChannel:
* 这里以服务端向客户端发送数据来举例
*/
@Override
public ChannelFuture writeAndFlush(Object msg) {
/*
需要注意的是:这里拿到的pipeline就是在服务端有我们自定义handler的pipeline,
也就是NioServerSocketChannel的pipeline
*/
return pipeline.writeAndFlush(msg);
}
/**
* DefaultChannelPipeline:
*/
@Override
public final ChannelFuture writeAndFlush(Object msg) {
//因为是出站事件,所以从tail开始遍历所有的outboundHandler
return tail.writeAndFlush(msg);
}
/**
* AbstractChannelHandlerContext:
*/
@Override
public ChannelFuture writeAndFlush(Object msg) {
return writeAndFlush(msg, newPromise());
}
@Override
public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) {
write(msg, true, promise);
return promise;
}
private void write(Object msg, boolean flush, ChannelPromise promise) {
ObjectUtil.checkNotNull(msg, "msg");
try {
if (isNotValidPromise(promise, true)) {
ReferenceCountUtil.release(msg);
return;
}
} catch (RuntimeException e) {
ReferenceCountUtil.release(msg);
throw e;
}
//这里就是在找下一个执行写动作的outboundHandler
final AbstractChannelHandlerContext next = findContextOutbound(flush ?
(MASK_WRITE | MASK_FLUSH) : MASK_WRITE);
final Object m = pipeline.touch(msg, next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
if (flush) {
//传进来的flush为true,所以走下面的方法
next.invokeWriteAndFlush(m, promise);
} else {
next.invokeWrite(m, promise);
}
} else {
final WriteTask task = WriteTask.newInstance(next, m, promise, flush);
if (!safeExecute(executor, task, promise, m, !flush)) {
task.cancel();
}
}
}
void invokeWriteAndFlush(Object msg, ChannelPromise promise) {
if (invokeHandler()) {
//这里就可以看到writeAndFlush方法是通过write和flush两个事件来执行的
invokeWrite0(msg, promise);
invokeFlush0();
} else {
writeAndFlush(msg, promise);
}
}
/**
* 第72行代码处:
*/
private void invokeWrite0(Object msg, ChannelPromise promise) {
try {
/*
这里拿到的handler是编码的handler,即StringEncoder、ObjectEncoder等等,
执行它写好的write方法就行了
*/
((ChannelOutboundHandler) handler()).write(this, msg, promise);
} catch (Throwable t) {
notifyOutboundHandlerException(t, promise);
}
}
/**
* 第73行代码处:
*/
private void invokeFlush0() {
try {
/*
这里的handler跟上面invokeWrite0方法的handler是同一个,也就是那个编码的handler,
执行它写好的flush方法即可(里面同时还会调用HeadContext的flush方法)
*/
((ChannelOutboundHandler) handler()).flush(this);
} catch (Throwable t) {
invokeExceptionCaught(t);
}
}
所谓心跳,即在TCP长连接中,客户端和服务器之间定期发送的一种特殊的数据包,通知对方自己还在线,以确保TCP连接的有效性。在Netty中,实现心跳机制的关键是IdleStateHandler(我之前写过一个Netty心跳检测的示例程序,感兴趣的可以查看《Netty实现心跳检测机制》)。
使用IdleStateHandler的方式也是十分简单,只需要在pipeline中添加就行了(还需要在后面的handler中加上超时的处理):
pipeline.addLast(new IdleStateHandler(3, 0, 0));
这里演示的是IdleStateHandler的readerIdleTime参数指定超过3秒还没收到客户端的连接,会触发IdleStateEvent事件并且交给下一个handler处理。所以下一个handler必须实现userEventTriggered方法处理对应的事件。
/**
* IdleStateHandler:
* <1>readerIdleTimeSeconds:读超时。即当在指定的时间间隔内没有从Channel中读取到数据时,会触发一个READER_IDLE的
* IdleStateEvent事件;
*
* <2>writerIdleTimeSeconds:写超时。即当在指定的时间间隔内没有数据写入到Channel时,会触发一个WRITER_IDLE的
* IdleStateEvent事件;
*
* <3>allIdleTimeSeconds:读写超时。即当在指定的时间间隔内没有读或写操作时,会触发一个ALL_IDLE的IdleStateEvent事件
*/
public IdleStateHandler(
int readerIdleTimeSeconds,
int writerIdleTimeSeconds,
int allIdleTimeSeconds) {
this(readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds,
TimeUnit.SECONDS);
}
public IdleStateHandler(
long readerIdleTime, long writerIdleTime, long allIdleTime,
TimeUnit unit) {
this(false, readerIdleTime, writerIdleTime, allIdleTime, unit);
}
public IdleStateHandler(boolean observeOutput,
long readerIdleTime, long writerIdleTime, long allIdleTime,
TimeUnit unit) {
ObjectUtil.checkNotNull(unit, "unit");
/*
该参数用来表示是否考虑出站特别慢的情况(可能是网络传输比较慢,也可能是客户端处理比较慢)。比如出站用了10秒,
而空闲时间是5秒,那么在数据还有没有处理完的时候,就已经触发了空闲超时事件。这明显是不合理的。但这里传进来的
observeOutput是false,也就是不考虑这种情况(如果需要考虑这种情况的话,调用带observeOutput参数的构造器
就行了)
*/
this.observeOutput = observeOutput;
//设置readerIdleTime、writerIdleTimeNanos和allIdleTimeNanos
if (readerIdleTime <= 0) {
readerIdleTimeNanos = 0;
} else {
readerIdleTimeNanos = Math.max(unit.toNanos(readerIdleTime), MIN_TIMEOUT_NANOS);
}
if (writerIdleTime <= 0) {
writerIdleTimeNanos = 0;
} else {
writerIdleTimeNanos = Math.max(unit.toNanos(writerIdleTime), MIN_TIMEOUT_NANOS);
}
if (allIdleTime <= 0) {
allIdleTimeNanos = 0;
} else {
allIdleTimeNanos = Math.max(unit.toNanos(allIdleTime), MIN_TIMEOUT_NANOS);
}
}
/**
* IdleStateHandler:
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//该方法会把定时任务放到eventLoop的任务队列中等待去执行
initialize(ctx);
//该处会调用下一个handler的channelActive方法
super.channelActive(ctx);
}
/**
* 第7行代码处:
*/
private void initialize(ChannelHandlerContext ctx) {
switch (state) {
case 1:
case 2:
return;
}
/*
state置为1表示已经初始化过了,同一次channelRead别处调用再进来就会在上面的代码中return了
(为2表示已经被销毁了,也直接退出)
*/
state = 1;
//如果observeOutput设置为true的话,需要记录一些出站缓冲区的相关信息,以考虑出站特别慢的情况
initOutputChanged(ctx);
//重置lastReadTime和lastWriteTime为当前时间
lastReadTime = lastWriteTime = ticksInNanos();
//如果readerIdleTimeNanos>0,就会把定时任务加到scheduledTaskQueue中
if (readerIdleTimeNanos > 0) {
readerIdleTimeout = schedule(ctx, new ReaderIdleTimeoutTask(ctx),
readerIdleTimeNanos, TimeUnit.NANOSECONDS);
}
//如果writerIdleTimeNanos>0,就会把定时任务加到scheduledTaskQueue中
if (writerIdleTimeNanos > 0) {
writerIdleTimeout = schedule(ctx, new WriterIdleTimeoutTask(ctx),
writerIdleTimeNanos, TimeUnit.NANOSECONDS);
}
//如果allIdleTimeNanos>0,就会把定时任务加到scheduledTaskQueue中
if (allIdleTimeNanos > 0) {
allIdleTimeout = schedule(ctx, new AllIdleTimeoutTask(ctx),
allIdleTimeNanos, TimeUnit.NANOSECONDS);
}
}
/**
* 第28行代码处:
*/
private void initOutputChanged(ChannelHandlerContext ctx) {
if (observeOutput) {
Channel channel = ctx.channel();
Channel.Unsafe unsafe = channel.unsafe();
ChannelOutboundBuffer buf = unsafe.outboundBuffer();
/*
这里会记录一些出站缓冲区的相关信息(缓冲对象的hashCode、buf剩余待写的字节数和当前信息的刷新进度),
为了后面的hasOutputChanged方法做判断用
*/
if (buf != null) {
lastMessageHashCode = System.identityHashCode(buf.current());
lastPendingWriteBytes = buf.totalPendingWriteBytes();
lastFlushProgress = buf.currentProgress();
}
}
}
/**
* 第34行、第39行、第44行、第102行、第124行、第140行、第163行、第184行和第208行代码处:
*/
ScheduledFuture schedule(ChannelHandlerContext ctx, Runnable task, long delay, TimeUnit unit) {
/*
可以看到这里也是调用了schedule方法。之前已经分析过了,该方法会把任务放进scheduledTaskQueue中,
后续再去等线程执行runAllTasks方法,把任务拿出来再执行
*/
return ctx.executor().schedule(task, delay, unit);
}
/**
* 第34行代码处:
* ReaderIdleTimeoutTask的run方法,定时任务最终会走到这里
*/
@Override
protected void run(ChannelHandlerContext ctx) {
long nextDelay = readerIdleTimeNanos;
if (!reading) {
/*
ticksInNanos方法是用来获取当前时间,减去上次channelRead的时间表示的就是距离上次channelRead
后已经过了多久了。这时候用设置好的read超时时间再去减的话,结果就是下次的超时时间(注意:这一步是发生在
reading为false,也就是channelRead方法执行完毕的时候)
*/
nextDelay -= ticksInNanos() - lastReadTime;
}
if (nextDelay <= 0) {
/*
如上面所说,如果nextDelay<=0就说明已经到达或超过了超时时间。此时再次添加心跳任务进行下一次的心跳检测
从这里可以看出,Netty的心跳定时任务是通过循环调用schedule方法来添加任务,然后判断当前时间差来实现的
*/
readerIdleTimeout = schedule(ctx, this, readerIdleTimeNanos, TimeUnit.NANOSECONDS);
boolean first = firstReaderIdleEvent;
//firstReaderIdleEvent重新置为false
firstReaderIdleEvent = false;
try {
//构建一个READER_IDLE事件交给下面的userEventTriggered方法
IdleStateEvent event = newIdleStateEvent(IdleState.READER_IDLE, first);
/*
执行下一个handler的userEventTriggered方法(也就是我们必须要实现的方法)来处理超时
(该方法中就一行代码:ctx.fireUserEventTriggered(evt);)
*/
channelIdle(ctx, event);
} catch (Throwable t) {
ctx.fireExceptionCaught(t);
}
} else {
/*
如上面所说,如果nextDelay>0就说明此时还没有超时,那么就会把新的定时任务加到scheduledTaskQueue中
此时nextDelay为更新过的超时时间
*/
readerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
}
}
/**
* 第39行代码处:
* WriterIdleTimeoutTask的run方法,定时任务最终会走到这里
*/
@Override
protected void run(ChannelHandlerContext ctx) {
long lastWriteTime = this.lastWriteTime;
//和ReaderIdleTimeoutTask的run方法一样,更新一下此时的nextDelay
long nextDelay = writerIdleTimeNanos - (ticksInNanos() - lastWriteTime);
if (nextDelay <= 0) {
//如果nextDelay<=0就说明已经到达或超过了超时时间。此时再次添加心跳任务进行下一次的心跳检测
writerIdleTimeout = schedule(ctx, this, writerIdleTimeNanos, TimeUnit.NANOSECONDS);
boolean first = firstWriterIdleEvent;
//firstWriterIdleEvent重新置为false
firstWriterIdleEvent = false;
try {
//考虑出站特别慢的情况
if (hasOutputChanged(ctx, first)) {
return;
}
//构建一个WRITER_IDLE事件交给下面的userEventTriggered方法
IdleStateEvent event = newIdleStateEvent(IdleState.WRITER_IDLE, first);
//执行下一个handler的userEventTriggered方法(也就是我们必须要实现的方法)来处理超时
channelIdle(ctx, event);
} catch (Throwable t) {
ctx.fireExceptionCaught(t);
}
} else {
/*
如果nextDelay>0就说明此时还没有超时,那么就会把新的定时任务加到scheduledTaskQueue中
此时nextDelay为更新过的超时时间
*/
writerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
}
}
/**
* 第44行代码处:
* AllIdleTimeoutTask的run方法,定时任务最终会走到这里
*/
@Override
protected void run(ChannelHandlerContext ctx) {
long nextDelay = allIdleTimeNanos;
if (!reading) {
/*
同理,更新一下此时的nextDelay(注意:这一步是发生在reading为false,也就是channelRead方法
执行完毕的时候)
*/
nextDelay -= ticksInNanos() - Math.max(lastReadTime, lastWriteTime);
}
if (nextDelay <= 0) {
//如果nextDelay<=0就说明已经到达或超过了超时时间。此时再次添加心跳任务进行下一次的心跳检测
allIdleTimeout = schedule(ctx, this, allIdleTimeNanos, TimeUnit.NANOSECONDS);
boolean first = firstAllIdleEvent;
//firstAllIdleEvent重新置为false
firstAllIdleEvent = false;
try {
//考虑出站特别慢的情况
if (hasOutputChanged(ctx, first)) {
return;
}
//构建一个ALL_IDLE事件交给下面的userEventTriggered方法
IdleStateEvent event = newIdleStateEvent(IdleState.ALL_IDLE, first);
//执行下一个handler的userEventTriggered方法(也就是我们必须要实现的方法)来处理超时
channelIdle(ctx, event);
} catch (Throwable t) {
ctx.fireExceptionCaught(t);
}
} else {
/*
如果nextDelay>0就说明此时还没有超时,那么就会把新的定时任务加到scheduledTaskQueue中
此时nextDelay为更新过的超时时间
*/
allIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);
}
}
/**
* 第148行和第192行代码处:
*/
private boolean hasOutputChanged(ChannelHandlerContext ctx, boolean first) {
//如果observeOutput为false,也就是不考虑出站特别慢,就直接返回false
if (observeOutput) {
/*
如果最后记录的时间和上一次记录的不同,说明此时是第一次进入该方法,或者可能是写操作已经完成了,
更新了lastWriteTime。此时重新更新一下lastChangeCheckTimeStamp
*/
if (lastChangeCheckTimeStamp != lastWriteTime) {
lastChangeCheckTimeStamp = lastWriteTime;
/*
如果在出站处理完成之前又触发了下一次的定时任务,从而走到这里的话,first就是false
也就是说在定时任务两次调用hasOutputChanged方法的过程中,出站事件一直在处理中、没有执行
完毕。那么此时就直接返回true,后面也不会再处理userEventTriggered方法,直到出站结束
*/
if (!first) {
return true;
}
}
Channel channel = ctx.channel();
Unsafe unsafe = channel.unsafe();
ChannelOutboundBuffer buf = unsafe.outboundBuffer();
if (buf != null) {
//如果出站缓冲区有数据的话,说明之前在initOutputChanged方法中记录了这些信息,此时再次获取这些信息进行比对
int messageHashCode = System.identityHashCode(buf.current());
long pendingWriteBytes = buf.totalPendingWriteBytes();
//如果不等,说明缓冲区的数据在慢慢发生变化,也就是出站特别慢的情况。此时重新更新一下这些值
if (messageHashCode != lastMessageHashCode || pendingWriteBytes != lastPendingWriteBytes) {
lastMessageHashCode = messageHashCode;
lastPendingWriteBytes = pendingWriteBytes;
/*
走到这里还是要判断一下first的值,如果为false(不是第一次调用),就不会触发下一个handler的
userEventTriggered方法;如果为true(第一次调用),就会触发。按照原先设想的逻辑:如果发现
出站特别慢,那么此时就不应该去触发userEventTriggered方法,静静等待出站完毕就好了。那么为什么
第一次调用的时候需要触发呢?其实这里是Netty设计者的考虑。如果真的是发生了出站特别慢的情况,
很可能会引发后续的OOM。所以这里第一次调用会触发userEventTriggered方法,从而给使用者一个警告
如果这里不触发,从而最终可能发生OOM的话,可能会花费很大的功夫才能找到原来是出站特别慢(可能是
网络传输比较慢,也可能是客户端处理比较慢)才导致的OOM
*/
if (!first) {
return true;
}
}
/*
lastFlushProgress属性是4.1.x版本中新加的,之前4.0.x版本中没有这个属性。添加的原因详见
https://github.com/netty/netty/commit/51112e2b36ec5550a73d72bfc59f4523f7b8ec27
*/
long flushProgress = buf.currentProgress();
if (flushProgress != lastFlushProgress) {
lastFlushProgress = flushProgress;
//同上面的解释
if (!first) {
return true;
}
}
}
}
return false;
}
/**
* IdleStateHandler:
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (readerIdleTimeNanos > 0 || allIdleTimeNanos > 0) {
/*
reading为true表示channelRead方法还在执行中,在channelReadComplete方法中会重置为false,
也就是channelRead方法执行完毕了
*/
reading = true;
//每一次channelRead进来的时候都会将firstReaderIdleEvent和firstAllIdleEvent置为true
firstReaderIdleEvent = firstAllIdleEvent = true;
}
/*
该处会调用下一个handler的channelRead方法,也就是IdleStateHandler的channelRead方法并没有做什么
实际的事情,只是更改了一些标志位而已
*/
ctx.fireChannelRead(msg);
}