概述
本章主要讲解netty启动后的新连接的接入,当服务端的NioEventLoop启动后,selector会一直调用select方法,当监测到新的连接时,会创建客户端的NioSocketChanne,并从workGroup中分配出一个NioEventLoop,并注册到对应的selector上
一.新连接监测
在上篇文章# netty源码分析(三):NioEventLoop中的4.1章节中已经讲解eventLoop启动并监测IO事件
这里我们可以使用telnet 模拟一个客户端的连接
telnet 127.0.0.1 8888
最终会调用
NioEventLoop类
unsafe.close(unsafe.voidPromise());
读取channel中的数据是unsafe类,服务端的unsafe类是NioMessageUnsafe
public void read() {
//...省略边缘代码
do {
// 1. 这里读取连接,创建NioSocketChannel
int localRead = doReadMessages(readBuf);
if (localRead == 0) {
break;
}
if (localRead < 0) {
closed = true;
break;
}
allocHandle.incMessagesRead(localRead);
} while (allocHandle.continueReading());
int size = readBuf.size();
for (int i = 0; i < size; i ++) {
readPending = false;
//2.触发channel中channelRead方法,就是分配NioEventLoop和注册Selector
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 {
if (!readPending && !config.isAutoRead()) {
removeReadOp();
}
}
}
1.1.NioSocketChannel创建
通过上面代码,
//在这里,创建
int localRead = doReadMessages(readBuf);
接着进入,在这里调用jdk底层,创建 NioSocketChannel
new NioSocketChannel(this, ch)
在new这个对象时候,第一个参数是NioServerSocketChannel作为父chanle,第二个参数是jdk的SocketChannel,代码如下
会一层一层的调用父类构造,最后创建一个NioSocketChannel,这里和创建NioServerSocketChannel代码逻辑是一样的,因为他们有共同的父类,不同的是,这里关注的事件是OP_READ事件
1.2.新链接的NioEventLoop的分配和selector注册
新的连接创建成功后,会把新的连接放入readBuf集合中,然后遍历该集合,依次触发方法
pipeline.fireChannelRead(readBuf.get(i))
fireChannelRead方法,会在这个channel中,从head开始,依次触发每个handler的read方法,会依次进入 Head --> MyServerHandler -->ServerBootstrapAcceptor
在ServerBootstrapAcceptor中,会对这个客户端连接,进行NioEventLoop的分配和selector注册
进入第五步,注册
childGroup.register(child)
继续进入
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
1. next()方法是从选择器中选择一个对象,这个前面讲过了
2. 选好之后,调用jdk底层channel进行注册,这个和服务端的channel注册逻辑是一样的,前面文章已经讲过了
public ChannelFuture register(Channel channel) {
return register(new DefaultChannelPromise(channel, this));
}
注册到select后,现在pipline中的hadler情况如下
HeadHandler --> MyTcpServerInitializer 启动类自己添加的 ---> TailHandler
但是我们知道 MyTcpServerInitializer 启动类自己添加的 里面有个 initChannel(socketchannel)方法,在这个方法里面,我们才真正添加处理业务的handler,那么MyTcpServerInitializer的initChannel(socketchannel)方法是什么时候执行的呢? 答案就是把这个channle注册到select后,如下所示
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !this.ensureOpen(promise)) {
return;
}
boolean firstRegistration = this.neverRegistered;
AbstractChannel.this.doRegister();
this.neverRegistered = false;
AbstractChannel.this.registered = true;
AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded(); // todo 这里会触发handleradd,最终触发initChannel方法
this.safeSetSuccess(promise);
AbstractChannel.this.pipeline.fireChannelRegistered();
if (AbstractChannel.this.isActive()) {
if (firstRegistration) {
AbstractChannel.this.pipeline.fireChannelActive();
} else if (AbstractChannel.this.config().isAutoRead()) {
this.beginRead();
}
}
} catch (Throwable var3) {
this.closeForcibly();
AbstractChannel.this.closeFuture.setClosed();
this.safeSetFailure(promise, var3);
}
}
最终会调用
二.NioSocketChannel读写事件的注册
后面在写,心累了