前一篇,提到NioServerSocketChannel注册到eventloop中,eventloop就是接受客户端请求的代码。
eventloop作用是一个不断地循环,循环主要做三件事情:
1.有条件地等待Nio事件
2.处理Nio事件
3.处理队列中的任务
我们找到run代码里的processSelectedKeys(),这里是处理各种事件的。追踪发现最后调用的是private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) ;我们看看代码。
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 {
int readyOps = k.readyOps();
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) {
// Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
ch.unsafe().forceFlush();
}
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
// 这里是处理OP_ACCEPT事件的
unsafe.read();
}
} catch (CancelledKeyException ignored) {
unsafe.close(unsafe.voidPromise());
}
}
点进去NioMeesageUnsafe的read方法,里面调用了NioServerSocketChannel的doReadMessages(List buf)。
protected int doReadMessages(List<Object> buf) throws Exception {
// 接受一个连接,底层就是JDK的accepet
SocketChannel ch = SocketUtils.accept(javaChannel());
try {
if (ch != null) {
// 将接收的socketChannel放入list返回
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;
}
之后将buf中循环地调用pipeline.fireChannelRead(buf.get(i));
下面分析pipeline的fireChannelRead(Object msg) 方法
@Override
public final ChannelPipeline fireChannelRead(Object msg) {
// head是pipeline的头节点,是HeadContext实例
AbstractChannelHandlerContext.invokeChannelRead(head, msg);
return this;
}
// 最后我们追到这个函数
private void invokeChannelRead(Object msg) {
if (invokeHandler()) {
try {
// ctx是handler的包装类,所以我们直接看HeadConxtex的handler的channelRead
((ChannelInboundHandler) handler()).channelRead(this, msg);
} catch (Throwable t) {
notifyHandlerException(t);
}
} else {
fireChannelRead(msg);
}
}
// HeadContext的handler就是它本身,所以我们直接看HeadContext的channelRead
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// 发现它调用的ctx的fireChannelRead
ctx.fireChannelRead(msg);
}
// ctx的fireChannelRead(Object)方法如下
@Override
public ChannelHandlerContext fireChannelRead(final Object msg) {
// findConrtextInboud()是找到当前ctx在pipeline的下一个
//invokeChannelRead即又回到了第一个函数那,又重新执行一遍上面的逻辑
// 所以,fireChannelRead的传递机制如下: 每个handler处理完之后调用ctx.fireChannelRead()
// 从而达到传递给下一个ctx的目的
invokeChannelRead(findContextInbound(), msg);
return this;
}
前一篇文章中,我们知道NioServerSocketChannel的pipeline是由head,LoggingHandler,ServerBootstrapAcceptor,tail组成。
ServerBootstrapAcceptor就是将客户端channel注册到从reactor的代码,其他handler都不是很重要。
下面看看ServerBootstrapAcceptor的channelRead方法
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// msg就是NioSocketChannel
final Channel child = (Channel) msg;
// 给NioSocketChannel设置handler
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
try {
// 将NioSocketChannel注册到workGroup中
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);
}
}
这里的childGroup.register(Channel)追踪进去和前文的regist一样,也就是说此时,该channel(NioSocketChannel)的事件已经注册到NioEventLoop中了。eventloop的任务之一就是select各种事件,自然包括客户端的可读事件,由此开始了服务端与客户端的数据传输。