根据上一次接收数据逻辑的学习,可以总结下面的流程,红色就是我们学习的地方。
pipeline,下面以inbound和outbound为例。pipeline本质就是一个链表,有head和tail,中间是很多个context,每个context中包含了需要执行的handler。可以看出inbound执行handle的顺序和outbound相反。
打断点到EventLoop的读取数据的部分
依然会进入到下面的代码,我们重点看pipeline.fireChannelRead(byteBuf);
这一行代码
@Override
public final void read() {
final ChannelConfig config = config();
if (shouldBreakReadReady(config)) {
clearReadPending();
return;
}
final ChannelPipeline pipeline = pipeline();
// 内存分配器
final ByteBufAllocator allocator = config.getAllocator();
// 接收数据测handler
final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
allocHandle.reset(config);
ByteBuf byteBuf = null;
boolean close = false;
try {
do {
// 分配内存是自适应的
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;
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();
}
}
}
}
从head头部开始查找Context,去执行其中的Handler
invokeChannelRead
方法中会找到下一个Context的线程池去执行当前的任务
一直跟进,在上一个Handler执行结束(也就是read事件完成以后),就会在pipeline上面寻找下一个Context
找到下一个Conetext之后会重复上面的操作,找到该Conetxet的NioEventLoop的线程池去执行该操作
最后就会跳转到用户自定的EchoServerHandler
的channelRead
方法中执行相关业务。