2、Netty之Client端注册&Connect事件&Read事件的关注

客户端启动流程基本跟server端保持一致。

private void register0(ChannelPromise promise) {
    // check if the channel is still open as it could be closed in the mean time when the register
    // call was outside of the eventLoop
    if (!promise.setUncancellable() || !ensureOpen(promise)) {
        return;
    }
    boolean firstRegistration = neverRegistered;
    doRegister();
    neverRegistered = false;
    registered = true;
    pipeline.invokeHandlerAddedIfNeeded();

    safeSetSuccess(promise);
    pipeline.fireChannelRegistered();
    if (isActive()) {
        if (firstRegistration) {
            pipeline.fireChannelActive();
        } else if (config().isAutoRead()) {
            beginRead();
        }
    }
}

pipeline.invokeHandlerAddedIfNeeded:回调用户自定义的initChannel方法,将用户自定义ChannelHandler添加到NioSocketChannel中的pipeline中。

safeSetSuccess:回调Bootstrap#doResolveAndConnect~operationComplete方法。将在NioSocketChannel绑定Connect事件任务添加到普通队列中。

1、NioSocketChannel之Connect事件的绑定

public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
	private static void doConnect(
	        final SocketAddress remoteAddress, final SocketAddress localAddress, final ChannelPromise connectPromise) {
	
	    // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up
	    // the pipeline in its channelRegistered() implementation.
	    final Channel channel = connectPromise.channel();
	    channel.eventLoop().execute(new Runnable() {
	        @Override
	        public void run() {
	            if (localAddress == null) {
	                channel.connect(remoteAddress, connectPromise);// 绑定Connect事件
	            } else {
	                channel.connect(remoteAddress, localAddress, connectPromise);
	            }
	            connectPromise.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
	        }
	    });
	}
}
public class NioSocketChannel{
	protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception {
	    if (localAddress != null) {
	        doBind0(localAddress);
	    }
	
	    boolean success = false;
	    try {
	        boolean connected = SocketUtils.connect(javaChannel(), remoteAddress);// 跟服务端建立连接~ TCP协议
	        if (!connected) {
	            selectionKey().interestOps(SelectionKey.OP_CONNECT);//绑定注册 OP_CONNECT = 8 连接事件
	        }
	        success = true;
	        return connected;
	    } finally {
	        if (!success) {
	            doClose();
	        }
	    }
	}
}

利用TCP协议客户端与服务端建立连接。此时服务端会在NioServerSocketChannel对应SelectedKey上监测到对应的连接事件。

不理解的现象:当NioSocketChannel绑定连接事件后,在其事件循环组中会监测到该IO事件,区别于服务端绑定Accept事件。通过processSelectedKeys方法处理其上的IO事件时触发channelActive方法。

2、channelActive之发送客户端数据

private void processSelectedKeys() {
    if (selectedKeys != null) {
        processSelectedKeysOptimized();
    } else {
        processSelectedKeysPlain(selector.selectedKeys());
    }
}

private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
        final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
       	...
		int readyOps = k.readyOps();
        // We first need to call finishConnect() before try to trigger a read(...) or write(...) as otherwise
        // the NIO JDK channel implementation may throw a NotYetConnectedException.
        if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
            // remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
            // See https://github.com/netty/netty/issues/924
            int ops = k.interestOps();
            ops &= ~SelectionKey.OP_CONNECT;
            k.interestOps(ops);
            unsafe.finishConnect();//此处会触发channelActive 方法的执行,客户端通过通道发送数据到服务端
        }

        // Process OP_WRITE first as we may be able to write some queued buffers and so free memory.
        if ((readyOps & SelectionKey.OP_WRITE) != 0) {
            // Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
            ch.unsafe().forceFlush();
        }

        // Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
        // to a spin loop
        if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
            unsafe.read();
        }
    }

待续:分析客户端、服务端数据具体交互流程。

你可能感兴趣的:(网络)