NioEventLoop:
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) {
// If the channel implementation throws an exception because there is no event loop, we ignore this
// because we are only trying to determine if ch is registered to this event loop and thus has authority
// to close ch.
return;
}
// Only close ch if ch is still registered to this EventLoop. ch could have deregistered from the event loop
// and thus the SelectionKey could be cancelled as part of the deregistration process, but the channel is
// still healthy and should not be closed.
// See https://github.com/netty/netty/issues/5125
if (eventLoop == this) {
// close the channel if the key is not valid anymore
unsafe.close(unsafe.voidPromise());
}
return;
}
try {
int readyOps = k.readyOps();
// We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise
// the NIO JDK channel implementation may throw a NotYetConnectedException.
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
// remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
// See https://github.com/netty/netty/issues/924
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops);
unsafe.finishConnect();
}
// Process OP_WRITE first as we may be able to write some queued buffers and so free memory.
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
// Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
unsafe.forceFlush();
}
// Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
// to a spin loop
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
// unsafe 是 boss 线程中 NioServerSocketChannel 的 AbstractNioMessageChannel$NioMessageUnsafe 对象
unsafe.read();
}
} catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise());
}
}
进入 read 方法:
public void read() {
// 检查该 eventLoop 线程是否是当前线程
assert AbstractNioMessageChannel.this.eventLoop().inEventLoop();
ChannelConfig config = AbstractNioMessageChannel.this.config();
ChannelPipeline pipeline = AbstractNioMessageChannel.this.pipeline();
Handle allocHandle = AbstractNioMessageChannel.this.unsafe().recvBufAllocHandle();
allocHandle.reset(config);
boolean closed = false;
Throwable exception = null;
try {
int localRead;
try {
do {
// readBuf 是一个 List, 即容器
// 是读取boss 线程中的 NioServerSocketChannel 接受到的请求.并把这些请求放进容器
localRead = AbstractNioMessageChannel.this.doReadMessages(this.readBuf);
if (localRead == 0) {
break;
}
if (localRead < 0) {
closed = true;
break;
}
allocHandle.incMessagesRead(localRead);
} while(allocHandle.continueReading());
} catch (Throwable var11) {
exception = var11;
}
localRead = this.readBuf.size();
for(int i = 0; i < localRead; ++i) {
AbstractNioMessageChannel.this.readPending = false;
pipeline.fireChannelRead(this.readBuf.get(i));
}
this.readBuf.clear();
allocHandle.readComplete();
pipeline.fireChannelReadComplete();
if (exception != null) {
closed = AbstractNioMessageChannel.this.closeOnReadError(exception);
pipeline.fireExceptionCaught(exception);
}
if (closed) {
AbstractNioMessageChannel.this.inputShutdown = true;
if (AbstractNioMessageChannel.this.isOpen()) {
this.close(this.voidPromise());
}
}
} finally {
if (!AbstractNioMessageChannel.this.readPending && !config.isAutoRead()) {
this.removeReadOp();
}
}
}
进入 doReadMessages 方法:
protected int doReadMessages(List<Object> buf) throws Exception {
// 调用 NioServerSocketChannel 内部封装的 serverSocketChannel 的 accept 方法
// 获取到 一个 JDK 的 SocketChannel
SocketChannel ch = SocketUtils.accept(this.javaChannel());
try {
if (ch != null) {
// 使用 NioSocketChannel 进行封装,然后添加到容器中
buf.add(new NioSocketChannel(this, ch));
return 1;
}
} catch (Throwable var6) {
logger.warn("Failed to create a new channel from an accepted socket.", var6);
try {
ch.close();
} catch (Throwable var5) {
logger.warn("Failed to close a socket.", var5);
}
}
return 0;
}
进入 fireChannelRead 方法:
public final ChannelPipeline fireChannelRead(Object msg) {
AbstractChannelHandlerContext.invokeChannelRead(this.head, msg);
return this;
}
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRead(m);
} else {
executor.execute(new Runnable() {
public void run() {
next.invokeChannelRead(m);
}
});
}
}
private void invokeChannelRead(Object msg) {
if (this.invokeHandler()) {
try {
// 会反复执行handler 的 ChannelRead, pipeline中出现4个 handler, 分别是 Head, LoggingHandler, ServerBootstrapAcceptor, Tail
((ChannelInboundHandler)this.handler()).channelRead(this, msg);
} catch (Throwable var3) {
this.invokeExceptionCaught(var3);
}
} else {
this.fireChannelRead(msg);
}
}
进入 ServerBootstrapAcceptor 的 ChannelRead 方法:
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// msg 强转成 Channel, 实际上就是 NioSocketChannel
final Channel child = (Channel) msg;
// 添加 NioSocketChannel 的 pipeline 的 handler,就是我们 main 方法里设置的 childHandler 方法里的
child.pipeline().addLast(childHandler);
// 设置 NioSocketChannel 的各种属性
setChannelOptions(child, childOptions, logger);
setAttributes(child, childAttrs);
try {
// 将客户端连接注册到 worker 线程池
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);
}
}
进入 register 方法:
// MultithreadEventLoopGroup
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
// MultithreadEventLoopGroup
public EventLoop next() {
return (EventLoop) super.next();
}
// MultithreadEventExecutorGroup
public EventExecutor next() {
return chooser.next();
}
// GenericEventExecutorChooser
public EventExecutor next() {
return executors[(int) Math.abs(idx.getAndIncrement() % executors.length)];
}
// SingleThreadEventLoop
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
// SingleThreadEventLoop
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
promise.channel().unsafe().register(this, promise);
return promise;
}
// AbstractChannel
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;
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);
}
}
}
进入到 doBeginRead方法:
/**
* AbstractNioChannel 类的方法
* 对于这个客户端的连接就完成了,接下来就可以监听读事件了
*/
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) {
selectionKey.interestOps(interestOps | readInterestOp);
}
}
过程梳理:
总体流程:接受连接 --> 创建一个新的 NioSocketChannel --> 注册到一个 worker EventLoop 上 --> 注册 selector Read 事件
- 服务器轮询 Accept 事件, 获取事件后调用 unsafe 的 read 方法, 这个 unsafe 是 ServerSocket 的内部类,该方法内部由2部分组成
- doReadMessages 用于创建 NioSocketChannel 对象,该对象包装 JDK 的 Nio Channel 客户端。该方法会创建 ServerSocketChannel 类似创建相关的 pipeline, unsafe, config
- 随后执行 pipeline.fireChannelRead 方法,并将自己绑定到一个 chooser 选择器选择的 workerGroup 中的一个 EventLoop。 并且注册一个0, 表示注册成功, 但并没有注册读 (1) 事件