Netty学习笔记七
七. Netty源码
写的比较乱,请见谅。
1. 启动剖析
Nio流程
// 1. 创建Selector
Selector selector = Selector.open();
// 2. 创建serverSocketChannel
ServerSocketChannel ssc = ServerSocketChannel.open();
// 3. 将serverSocketChannel注册到selector上
SelectionKey selectionKey = ssc.register(selector, 0, nettySsc);
// 4. 绑定监听端口
ssc.bind(new InetSocketAddress(9090, backlog));
// 5. 设置感兴趣的事件
selectionKey.interestOps(SelectionKey.OP_ACCEPT);
Netty 流程简略分析
//1 netty 中使用 NioEventLoopGroup (简称 nio boss 线程)来封装线程和 selector
Selector selector = Selector.open();
//2 创建 NioServerSocketChannel,同时会初始化它关联的 handler,以及为原生 ssc 存储 config
NioServerSocketChannel attachment = new NioServerSocketChannel();
//3 创建 NioServerSocketChannel 时,创建了 java 原生的 ServerSocketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
//4 启动 nio boss 线程执行接下来的操作
//5 注册(仅关联 selector 和 NioServerSocketChannel),未关注事件
SelectionKey selectionKey = serverSocketChannel.register(selector, 0, attachment);
//6 head -> 初始化器 -> ServerBootstrapAcceptor -> tail,初始化器是一次性的,只为添加 acceptor
//7 绑定端口
serverSocketChannel.bind(new InetSocketAddress(8080));
//8 触发 channel active 事件,在 head 中关注 op_accept 事件
selectionKey.interestOps(SelectionKey.OP_ACCEPT);
bind方法概述
服务端代码
package com.sunyang.netty.study.nettydemo;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;
/**
* @program: netty-study
* @description: 源码分析
* @author: SunYang
* @create: 2021-08-25 13:52
**/
public class NettySourceServer {
public static void main(String[] args) {
new ServerBootstrap()
.group(new NioEventLoopGroup()) // Selector selector = Selector.open();
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>(){
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new LoggingHandler());
}
}).bind(8080);
}
}
【AbstractBootstrap.java】
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) {
// init ----> ServerSocketChannel ssc = ServerSocketChannel.open() main主线程
// Register ---> SelectionKey selectionKey = ssc.register(selector, 0, nettySsc);由Nio线程去执行
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
if (regFuture.isDone()) {
// 进入此处说明我们知道初始化和注册完成并成功。
ChannelPromise promise = channel.newPromise();
// 同步执行dobind0方法,由main线程
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
// 进入此处说明还没注册完成就会由Nio线程进行异步调用dobind0
// 由于注册耗时时间较长,所以很大几率是进入此处,由Nio线程回调doBind0去执行
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
// 异步去执行doBind0 由Nio线程去执行
// serverSocketChannel.bind(new InetSocketAddress(8080));
regFuture.addListener(new ChannelFutureListener() {
// 此处回调dobind0;
@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;
}
}
initAndRegister()
final ChannelFuture initAndRegister() {
Channel channel = null;
// 1. init 创建channel 并初始化handler
try {
// 1.1 创建 channel
channel = channelFactory.newChannel();
// 1.2 初始化handler
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);
}
// 2. register 注册channel
ChannelFuture regFuture = config().group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
1.1 channel = channelFactory.newChannel();
public T newChannel() {
try {
// 利用反射获取构造器创建实例
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
public NioServerSocketChannel() {
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>.
*/
// 创建了一个原生的ServerSocketChannel
// 等于Nio中的ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()
return provider.openServerSocketChannel();
} catch (IOException e) {
throw new ChannelException(
"Failed to open a server socket.", e);
}
}
1.2 init(channel)
@Override
void init(Channel channel) {
setChannelOptions(channel, newOptionsArray(), logger);
setAttributes(channel, newAttributesArray());
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
// 在流水线中添加了一个(ChannelInitializer<Channel>)handler他只会执行一次,这次只是加入到流水上,并没有执行initChannel().
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
// 保证此任务也在NIo线程中执行。
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
// 向NioServerSocketChannel中加入了Acceptor handler (在accept事件发生后建立连接。)
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
2.1 config().group().register(channel);
@Override
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
@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;
}
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;
}
AbstractChannel.this.eventLoop = eventLoop;
// 之前都是在main线程中执行, 在这里要进行线程切换
// 判断当前线程是否是Nio线程,当前为main线程,所以会进入到else中
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
// 将register0 封装到任务对象中,然后交给EventLoop去执行。
// 懒加载,调用execute时才会创建Nio Boss线程。
eventLoop.execute(new Runnable() {
@Override
public void run() {
// 切换成NIo 线程,执行此方法
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);
}
}
}
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
// 执行doRegister
doRegister();
neverRegistered = false;
registered = true;
// 注册完毕后调用
// 调用初始化handler(就是上一步只是添加了,但是未执行初始化。) 的initChannel 方法()
pipeline.invokeHandlerAddedIfNeeded();
// 给promise设置成功的结果。然后主线程哪里就可以通过回调获得结果。
safeSetSuccess(promise);
pipeline.fireChannelRegistered();
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
} catch (Throwable t) {
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
// SelectionKey selectionKey = ssc.register(selector, 0, nettySsc
// 并未关联事件
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
eventLoop().selectNow();
selected = true;
} else {
throw e;
}
}
}
}
doBind0()
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
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());
}
}
});
}
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.");
}
boolean wasActive = isActive();
try {
// 端口号的绑定
doBind(localAddress);
} catch (Throwable t) {
safeSetFailure(promise, t);
closeIfClosed();
return;
}
// 判断端口是否可用
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
// 触发流水线上的每个handler的active事件
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
// 进行端口绑定,并设置全连接队列大小。
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
public void channelActive(ChannelHandlerContext ctx)
// 关注accept事件
ctx.fireChannelActive();
readIfIsAutoRead();
}
protected void doBeginRead() throws Exception {
// Channel.read() or ChannelHandlerContext.read() was called
final SelectionKey selectionKey = this.selectionKey;
if (!selectionKey.isValid()) {
return;
}
readPending = true;
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
// 关注accept事件。
selectionKey.interestOps(interestOps | readInterestOp);
}
}
至此执行结束
执行图
NioEventLoop
1)组成
// NioEventLoop.java
private Selector selector;
private Selector unwrappedSelector;
// 父类 SingleThreadEventExecutor.java
private final Queue<Runnable> taskQueue; // 任务队列 ,单线程所以如果有多个任务,就需要任务队列
private volatile Thread thread; // 线程
private final Executor executor; // 单线程的执行器,可以理解为单线程的线程池。可以提交任务和添加定时任务 。和上面的线程是一个线程,只不过这个功能多。
// 曾祖父类 AbstractScheduledEventExecutor.java
PriorityQueue<ScheduledFutureTask<?>> scheduledTaskQueue; // 处理定时任务的任务队列
2)selector何时创建
在构造方法调用时
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler,
EventLoopTaskQueueFactory taskQueueFactory, EventLoopTaskQueueFactory tailTaskQueueFactory) {
super(parent, executor, false, newTaskQueue(taskQueueFactory), newTaskQueue(tailTaskQueueFactory),
rejectedExecutionHandler);
this.provider = ObjectUtil.checkNotNull(selectorProvider, "selectorProvider");
this.selectStrategy = ObjectUtil.checkNotNull(strategy, "selectStrategy");
final SelectorTuple selectorTuple = openSelector(); // 此处创建
this.selector = selectorTuple.selector;
this.unwrappedSelector = selectorTuple.unwrappedSelector;
}
2.1 为什么会有两个selector
private Selector selector;
private Selector unwrappedSelector;
为了在遍历selectedKeys提高性能,进行优化,JDK的selectedKeys是用set存储的,遍历性能差,而Netty用的是数组。
3)EventLoop的Nio线程在何时启动
当首次调用execute方法时会启动EventLoop的Nio线程,并且只会启动一次。
通过状态位控制线程不会被重复启动。
package com.sunyang.netty.study.nettydemo;
import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
/**
* @program: netty-study
* @description: EventLoop何时启动
* @author: SunYang
* @create: 2021-08-25 16:41
**/
public class EventLoopStartDemo {
public static void main(String[] args) {
EventLoop eventLoop = new NioEventLoopGroup().next();
// 在第一次调用execute时被创建
eventLoop.execute(() -> {
System.out.println("hello");
});
}
}
private void doStartThread() {
assert thread == null;
// 执行器(单线程的线程池) Nio线程
executor.execute(new Runnable() {
@Override
public void run() {
// 将当前执行器中的线程(就是Nio线程)赋值给了thread
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
// NioEventLoop的run() 方法
// 死循环去查看有没有任务,定时任务,IO事件。
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
......
4)提交普通任务会不会结束select阻塞。
Netty底层使用的是带超时的select(timeoutMillis)方法,时间到了会结束阻塞
提交普通任务的时候也会调用selectot.wakeup()方法,所以会结束阻塞,并执行普通任务。
4.1 wakeup方法中的代码如何理解
protected void wakeup(boolean inEventLoop) {
// 1. 当前执行提交任务的线程(执行wakeup的线程)和我EventLoop中的Nio线程是否是同一个线程,也就是只有其他线程提交任务时,才会唤醒selector,如果是Nio线程自己,并不需要唤醒,因为在EventLoop内部自己有唤醒机制。
// 2. wakenUp 原子布尔变量,用CAS设置值,作用
if (!inEventLoop && wakenUp.compareAndSet(false, true)) { // 4.1.39版本
selector.wakeup();
}
if (!inEventLoop && nextWakeupNanos.getAndSet(AWAKE) != AWAKE) { // 4.1.66 版本
selector.wakeup();
}
}
4.2 wakenUp变量的作用是什么
因为wakeUp是个重量级操作。
如果有多个其他线程都来提交任务,为了避免频繁调用wakeUp方法,所以用原子变量来控制在多线程情况下只有一个线程能成功调用wakeUp()方法。
5)每次循环时,什么时候会进入SelectStrategy.SELECT分支,让select进入阻塞。
当没有任务时,才会进入SelectStrategy.SELECT分支
当有任务时,会调用selectNow()方法(顺便拿到IO事件), 然后执行普通任务和IO事件。
protected void run() {
for (;;) {
try {
try {
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE:
continue;
case SelectStrategy.BUSY_WAIT:
// fall-through to SELECT since the busy-wait is not supported with NIO
case SelectStrategy.SELECT:
select(wakenUp.getAndSet(false));
....
public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {
return hasTasks ? selectSupplier.get() : SelectStrategy.SELECT;
}
private final IntSupplier selectNowSupplier = new IntSupplier() {
@Override
public int get() throws Exception {
return selectNow();
}
};
5.1 select()方法会阻塞多久
没有任务时会进入阻塞,默认阻塞 1.5秒左右,
什么情况下会退出阻塞:
- 超时时间到了
- 有任务了
- 有事件发生了
private void select(boolean oldWakenUp) throws IOException {
Selector selector = this.selector;
try {
int selectCnt = 0;
long currentTimeNanos = System.nanoTime();
long selectDeadLineNanos = currentTimeNanos + this.delayNanos(currentTimeNanos);
while(true) {
long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;
// 什么时候退出此循环 当 超时时间过了,timeoutMillis为0或小于0时,就会结束循环,也就是结束阻塞
if (timeoutMillis <= 0L) {
if (selectCnt == 0) {
selector.selectNow();
selectCnt = 1;
}
break;
}
// 有任务时 ,也会退出循环。结束阻塞。
if (this.hasTasks() && this.wakenUp.compareAndSet(false, true)) {
selector.selectNow();
selectCnt = 1;
break;
}
// 有时间发生时。
int selectedKeys = selector.select(timeoutMillis);
++selectCnt;
if (selectedKeys != 0 || oldWakenUp || this.wakenUp.get() || this.hasTasks() || this.hasScheduledTasks()) {
break;
}
currentTimeNanos = time;
....
}
}
超时时间计算
long currentTimeNanos = System.nanoTime();
// 截止时间 = 当前时间 + 返回的时间 1秒(没有定时任务时)
long selectDeadLineNanos = currentTimeNanos + delayNanos(currentTimeNanos);
for (;;) {
// 超时时间 = 截止时间 - 当前时间 + 0.5 毫秒 = 1.5 秒
long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;
protected long delayNanos(long currentTimeNanos) {
ScheduledFutureTask<?> scheduledTask = peekScheduledTask();
// 如果没有定时任务,返回一个时间
if (scheduledTask == null) {
return SCHEDULE_PURGE_INTERVAL; // 1秒
}
// 如果有定时任务,返回下一个定时任务的执行时间
return scheduledTask.delayNanos(currentTimeNanos);
}
6)Nio空轮询BUG
JDK在Linux的selector下才会发生
Netty的解决方法
通过设置一个计数器,count(阈值) 来判断是否发生了空轮询,默认512 ,可以自己设置。
解决:重新创建一个selector。替换掉了旧的selector。
7)ioRatio控制什么,设置为100有何作用
ioRatio控制处理IO事件所占用的时间比例。默认50%。
如果把ioRatio设置为100,就是所有IO事件执行完,再执行普通任务,但是下一次IO事件就要等到所有的普通任务执行完。所以不要设置成100、
protected void run() {
for (;;) {
try {
try {
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE:
continue;
case SelectStrategy.BUSY_WAIT:
case SelectStrategy.SELECT:
select(wakenUp.getAndSet(false));
if (wakenUp.get()) {
selector.wakeup();
}
// fall through
default:
}
} catch (IOException e) {
rebuildSelector0();
handleLoopException(e);
continue;
}
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
if (ioRatio == 100) {
try {
processSelectedKeys();
} finally {
// Ensure we always run tasks.
runAllTasks();
}
} else {
// 记录执行IO事件的开始时间
final long ioStartTime = System.nanoTime();
try {
// 处理所有IO事件。
processSelectedKeys();
} finally {
// ioTime代表执行IO事件处理所耗费的时间。
final long ioTime = System.nanoTime() - ioStartTime;
// 然后处理所有普通任务。如果处理普通任务的时间过长,就会影响IO事件处理效率
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
}
} catch (Throwable t) {
handleLoopException(t);
}
}
8) selectedKeys集合优化
private void processSelectedKeys()
// 判断是否为空
if (selectedKeys != null) {
// 如果不为null, 证明Netty已经把selectedKeys集合底层替换掉了
processSelectedKeysOptimized();
} else {
// 如果不为null 走原始的selectedKeys集合
processSelectedKeysPlain(selector.selectedKeys());
}
}
private void processSelectedKeysOptimized() {
for (int i = 0; i < selectedKeys.size; ++i) {
final SelectionKey k = selectedKeys.keys[i];
// 拿到事件
selectedKeys.keys[i] = null;
// 拿到key上关联的附件(NioServerSocketChannel或NioSocketChannel)
// 要对key进行各种各样的处理(读,写等等),对这些处理就需要用到handler,所以通过附件拿到channel,然后拿到handler,进行处理。
final Object a = k.attachment();
if (a instanceof AbstractNioChannel) {
// 然后进行事件区分 - 9
processSelectedKey(k, (AbstractNioChannel) a);
} else {
@SuppressWarnings("unchecked")
NioTask<SelectableChannel> task = (NioTask<SelectableChannel>) a;
processSelectedKey(k, task);
}
if (needsToSelectAgain) {
// null out entries in the array to allow to have it GC'ed once the Channel close
// See https://github.com/netty/netty/issues/2363
selectedKeys.reset(i + 1);
selectAgain();
i = -1;
}
}
}
9)在哪里区分不同事件类型。
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 || eventLoop == null) {
return;
}
unsafe.close(unsafe.voidPromise());
return;
}
try {
// 是否是连接事件
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
unsafe.finishConnect();
}
// 是否是写事件
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
ch.unsafe().forceFlush();
}
// 是否是可读事件或者可连接事件
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read();
}
} catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise());
}
}
accept() 流程
NIO的Accept() 流程
Netty流程
前三步已经在EventLoop中执行完了
// 是否是可读事件或者可连接事件
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read(); // 将会把后面三件事执行完毕
}
执行到此,继续向下执行
public void read() {
assert eventLoop().inEventLoop();
final ChannelConfig config = config();
final ChannelPipeline pipeline = pipeline();
final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
allocHandle.reset(config);
boolean closed = false;
Throwable exception = null;
try {
try {
do {
// 创建SocketChannel,设置非阻塞
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;
// 拿到NioServerSocketChannel上的流水线,然后将刚刚建立的连接当成消息进行处理。
// ServerSocketChannel上的流水线 就只包括三个Handler head->acceptor->tail
// 然后由acceptor处理剩下的步骤:将SocketChannel注册至selector和关注read事件
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 {
// Check if there is a readPending which was not processed yet.
// This could be for two reasons:
// * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
// * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
//
// See https://github.com/netty/netty/issues/2254
if (!readPending && !config.isAutoRead()) {
removeReadOp();
}
}
}
}
protected int doReadMessages(List<Object> buf) throws Exception {
// 调用ServerSocketChannel.accept() 建立连接完毕
SocketChannel ch = SocketUtils.accept(javaChannel());
try {
if (ch != null) {
// 创建NioSocketChannel,并将建立连接的原生SocketChannel作为构造方法的参数传给了NioSocketChannel并设置为非阻塞
// 将NioSocketChannel当成一个消息,放到一个结果里,然后在handler中进行处理
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;
}
private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
final Channel child = (Channel) msg;
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
try {
// 要把一个新的NioEventLoop中的selector和NioSocketChannel进行绑定并监听事件。
// 并用这个NioEventLoop中的那个线程去执行NioSocketChannel的事件任务,因为执行当前accept事件的线程是NioServerSocketChannel的EventLoop的线程。所以在这里还要发生线程的切换,用新的这个线程去执行刚刚绑定的这个NioSocketChannel的事件。
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);
}
}
}
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
if (eventLoop == null) {
throw new NullPointerException("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;
}
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);
}
}
}
}
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
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
// 执行 注册操作 将SocketChannel注册至selector
doRegister();
neverRegistered = false;
registered = true;
// 触发ScoketChannel上的初始化事件ininChannel()
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
pipeline.fireChannelRegistered();
if (isActive()) {
if (firstRegistration) {
// 关注read事件
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
} catch (Throwable t) {
// Close the channel directly to avoid FD leak.
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
// 将原生的SocketChannel注册到eventLoop的selector上,并将NIoSocketChannel当作附件绑定
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;
}
}
}
}
read()流程
NIO的read() 流程
Netty的read() 流程
在此开始
// 是否是可读事件或者可连接事件
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read();
}
public abstract class AbstractNioByteChannel extends AbstractNioChannel {
public final void read() {
final ChannelConfig config = config();
if (shouldBreakReadReady(config)) {
clearReadPending();
return;
}
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);
// 从网络中读取数据
allocHandle.lastBytesRead(doReadBytes(byteBuf));
if (allocHandle.lastBytesRead() <= 0) {
// nothing was read. release the buffer.
byteBuf.release();
byteBuf = null;
close = allocHandle.lastBytesRead() < 0;
if (close) {
// There is nothing left to read as we received an EOF.
readPending = false;
}
break;
}
allocHandle.incMessagesRead(1);
readPending = false;
// 找到流水线,触发读事件,然后将数据依次传给handler,进行处理
pipeline.fireChannelRead(byteBuf);
byteBuf = null;
} while (allocHandle.continueReading());
allocHandle.readComplete();
pipeline.fireChannelReadComplete();
if (close) {
closeOnRead(pipeline);
}
} catch (Throwable t) {
handleReadException(pipeline, byteBuf, t, close, allocHandle);
} finally {
// Check if there is a readPending which was not processed yet.
// This could be for two reasons:
// * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
// * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
//
// See https://github.com/netty/netty/issues/2254
if (!readPending && !config.isAutoRead()) {
removeReadOp();
}
}
}
}
}
allocHandle.incMessagesRead(1);
readPending = false;
// 找到流水线,触发读事件,然后将数据依次传给handler,进行处理
pipeline.fireChannelRead(byteBuf);
byteBuf = null;
} while (allocHandle.continueReading());
allocHandle.readComplete();
pipeline.fireChannelReadComplete();
if (close) {
closeOnRead(pipeline);
}
} catch (Throwable t) {
handleReadException(pipeline, byteBuf, t, close, allocHandle);
} finally {
// Check if there is a readPending which was not processed yet.
// This could be for two reasons:
// * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
// * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
//
// See https://github.com/netty/netty/issues/2254
if (!readPending && !config.isAutoRead()) {
removeReadOp();
}
}
}
}
}