Netty客户端启动后服务端接收消息的流程
之前简单讲述了netty服务端启动的流程,客户端启动基本流程一致,今天我们简单介绍下服务端接收客户端发送的消息的过程
1、看下服务端启动和接收客户端连接时pipeline的构建图
2、客户端启动,处理select中事件
2.1、获取unsafe对象,
此时由于channel是NioServerSocketChannel,所以unsafe对象为NioMessageUnsafe类型
2.2、调用NioMessageUnsafe的read方法
2.3、调用doReadMessages
SocketUtils.accept方法中使用Java NIO的accept方法真正接受建链请求,和客户端建立连接后产生的socketChannel封装成NioSocketChannel,此时创建的unsafe类型为NioSocketChannelUnsafe其父类为NioByteUnsafe,此时构建文章开头的图片中的第二个pipeline对象DefaultChannelPipeline
接2.2图
3、调用pipeline的扩散消息方法,关注ServerBootstrapAcceptor处理消息方法
直接将msg强制转换为Channel对象,获取channel中的pipeline(channel和pipeline互相包含的)添加childHandler,最后注册此channel,注册的逻辑和之前一样
客户端channel写入数据时,服务端select继续循环处理事件,
此时unsafe为NioSocketChannelUnsafe,我们看下其父类的read方法
protected class NioByteUnsafe extends AbstractNioUnsafe {
...
@Override
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 = 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) {
readPending = false;
}
break;
}
allocHandle.incMessagesRead(1);
readPending = false;
//扩散消息
pipeline.fireChannelRead(byteBuf);
byteBuf = null;
} while (allocHandle.continueReading());
allocHandle.readComplete();
pipeline.fireChannelReadComplete();
...
}
}
pipeline.fireChannelRead(byteBuf);最后会调用我们自己写的NettyServerHandler处理msg