经过Netty源码分析(一):客户端操作之channel()和Netty源码分析(二):客户端操作之EventLoopGroup、group()、option()后,
Netty这时候大概初始化结束了,那么客户端是如何发起TCP连接的呢?
在channel方法中,我们调到connect方法会调用initAndRegister,初始化和注册channel,那么完毕且经过一些参数检查之后,最终会调用doConnect方法:
private static void doConnect(final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise connectPromise) {
//channel即SocketChannel
final Channel channel = connectPromise.channel();
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (localAddress == null) {
channel.connect(remoteAddress, connectPromise);
} else {
channel.connect(remoteAddress, localAddress, connectPromise);
}
connectPromise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
}
});
}
可以看到,此处开启了一个线程来调用connect方法
继续点进去connect,往下走:
AbstractChannel#connect->DefaultChannelPipeline#connect->AbstractChannelHandlerContext#connect
此链调用的是tail.connect方法,即AbstractChannelHandlerContext,因为tail没有实现connect方法:
public ChannelFuture connect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
final AbstractChannelHandlerContext next = findContextOutbound();
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeConnect(remoteAddress, localAddress, promise);
} else {
safeExecute(executor, new Runnable() {
@Override
public void run() {
next.invokeConnect(remoteAddress, localAddress, promise);
}
}, promise, null);
}
return promise;
}
此处又开始了一个线程,调用next的invokeConnect方法,最终会找到AbstractNioChannel.AbstractNioUnsafe#connect:
@Override
public final void connect(
final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise promise) {
boolean wasActive = isActive();
if (doConnect(remoteAddress, localAddress)) {
fulfillConnectPromise(promise, wasActive);
} else{}
}
看看doConnect方法:
protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
if (localAddress != null) {
doBind0(localAddress);
}
boolean success = false;
try {
boolean connected = javaChannel().connect(remoteAddress);//连接
if (!connected) {
selectionKey().interestOps(SelectionKey.OP_CONNECT);//状态改为connect
}
success = true;
return connected;
} finally {
if (!success) {
doClose();
}
}
}
总结一下:
最后,看看设计时序图:
NioEventLoop是线程池中的一个线程,重写了这些方法之后,一步步深入操作
NioSocketChannel类似IOC设计,由反射来生成实例
然后就是pipeline,生成一条链,保证执行顺序不会乱;而每个channel都会有单独一个线程来执行,形成并行,并行里的串行则是通过tail和head来控制的
AbstractNioUnsafe则做一下比如线程返回之类的操作
最终就调用了底层的connect方法
都是为了达到异步非阻塞的目的
涉及到装饰器模式、模板模式、责任链模式、工厂模式、反应堆