上接Netty源码分析之服务端启动流程,本节看下客户端启动的流程。
public class Client { private static final Logger LOGGER = LoggerFactory.getLogger(Client.class); private static String host = "127.0.0.1"; private static int port = 9090; public static void main(String[] args) { NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(eventLoopGroup) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new ClientChannelHandler()); } }).option(ChannelOption.TCP_NODELAY, true); try { bootstrap.connect(host, port).sync(); } catch (InterruptedException e) { e.printStackTrace(); } } }
NioEventLoopGroup和Bootstrap的初始化与服务端基本一致,重点关注下connect的流程。
public ChannelFuture connect(SocketAddress remoteAddress) { if (remoteAddress == null) { throw new NullPointerException("remoteAddress"); } else { this.validate(); return this.doResolveAndConnect(remoteAddress, this.config.localAddress()); } }
核心逻辑在doResolveAndConnect
private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) { ChannelFuture regFuture = this.initAndRegister(); final Channel channel = regFuture.channel(); if (regFuture.isDone()) { return !regFuture.isSuccess() ? regFuture : this.doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise()); } else { final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel); regFuture.addListener(new ChannelFutureListener() { public void operationComplete(ChannelFuture future) throws Exception { Throwable cause = future.cause(); if (cause != null) { promise.setFailure(cause); } else { promise.registered(); Bootstrap.this.doResolveAndConnect0(channel, remoteAddress, localAddress, promise); } } }); return promise; } }
1. this.initAndRegister
- 通过反射创建NioSocketChannel对象。
- 和NioServerSocketChannel端一样,NioSocketChannel实例化的时候内部会创建unsafe和pipeline对象,但是客户端unsafe的实例对象是NioSocketChannelUnsafe(前面提过,unsafe可以看作是Netty调用底层NIO的桥梁)。
- 注册SelectionKey.OP_READ事件
final ChannelFuture initAndRegister() { Channel channel = null; try { channel = this.channelFactory.newChannel(); this.init(channel); } catch (Throwable var3) { if (channel != null) { channel.unsafe().closeForcibly(); return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3); } return (new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE)).setFailure(var3); } ChannelFuture regFuture = this.config().group().register(channel); if (regFuture.cause() != null) { if (channel.isRegistered()) { channel.close(); } else { channel.unsafe().closeForcibly(); } } return regFuture; }从eventLooGroup选择一个线程处理channel注册,channel和当前线程被封装成了DefaultChannelPromise对象。
public ChannelFuture register(Channel channel) { return this.register((ChannelPromise)(new DefaultChannelPromise(channel, this))); }
启动线程执行注册AbstractUnsafe.this.register0(promise)
AbstractChannel.this.eventLoop = eventLoop; if (eventLoop.inEventLoop()) { this.register0(promise); } else { try { eventLoop.execute(new Runnable() { public void run() { AbstractUnsafe.this.register0(promise); } }); } catch (Throwable var4) { AbstractChannel.logger.warn("Force-closing a channel whose registration task was not accepted by an event loop: {}", AbstractChannel.this, var4); this.closeForcibly(); AbstractChannel.this.closeFuture.setClosed(); this.safeSetFailure(promise, var4); } }
- AbstractChannel.this.doRegister() 将当前socketChannel注册到selector上
- AbstractChannel.this.pipeline.fireChannelRegistered()在链表上传播register事件
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(); 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); } }
2. doResolveAndConnect
再回到Bootstrap,跟进doResolveAndConnect0方法
if (regFuture.isDone()) { return !regFuture.isSuccess() ? regFuture : this.doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise()); }
执行连接操作
doConnect((SocketAddress)resolveFuture.getNow(), localAddress, promise);从链表尾部开始传播connect事件,依次调用Outbound为True的Handler
public final ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise) { return this.tail.connect(remoteAddress, promise); }
最终调用了unsafe.connect方法
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception { this.unsafe.connect(remoteAddress, localAddress, promise); }
3. 服务端处理
connect完成之后,再来关注下服务端AbstractChannel.register0方法。
由于首次注册,会进入AbstractChannel.this.pipeline.fireChannelActive()
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(); 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); } }
链表上调用inbound为ture的Handler处理active事件
private void invokeChannelActive() { if (this.invokeHandler()) { try { ((ChannelInboundHandler)this.handler()).channelActive(this); } catch (Throwable var2) { this.notifyHandlerException(var2); } } else { this.fireChannelActive(); } }完成激活后,会调用readIfIsAutoRead
public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelActive(); this.readIfIsAutoRead(); }
从tail向head传播read事件
public final ChannelPipeline read() { this.tail.read(); return this; }
最终调用unsafe的beginRead方法,等待客户端数据到来
public void read(ChannelHandlerContext ctx) { this.unsafe.beginRead(); }