netty源码分析 - register分析

系列

Netty源码分析 - Bootstrap服务端
Netty源码分析 - Bootstrap客户端
netty源码分析 - ChannelHandler
netty源码分析 - EventLoop类关系
netty源码分析 - register分析
Netty源码分析 - NioEventLoop事件处理
netty源码分析 - accept过程分析
Netty源码分析 - ByteBuf
Netty源码分析 - 粘包和拆包问题


开篇

  • 这篇文章主要用于分析NioSocketChannel注册到NioEventLoop对象的过程,顺带和Nio的例子进行下对比。
  • 通过这篇文章能够了解到整个注册过程的脉络为NioEventLoopGroup => NioEventLoop => NioSocketChannel的刘哦吃。


Nio的例子

public class NioEchoServer {
    private static final int BUF_SIZE = 256;
    private static final int TIMEOUT = 3000;

    public static void main(String args[]) throws Exception {
        // 打开服务端 Socket,ServerSocketChannel.open()
        // 内部执行的是 SelectorProvider.provider().openServerSocketChannel();
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 打开 Selector
        Selector selector = Selector.open();

        // 服务端 Socket 监听8080端口, 并配置为非阻塞模式
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));
        serverSocketChannel.configureBlocking(false);

        // 将 channel 注册到 selector 中.
        // 通常我们都是先注册一个 OP_ACCEPT 事件, 然后在 OP_ACCEPT 到来时, 再将这个 Channel 的 OP_READ
        // 注册到 Selector 中.
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            // 通过调用 select 方法, 阻塞地等待 channel I/O 可操作
            if (selector.select(TIMEOUT) == 0) {
                System.out.print(".");
                continue;
            }

            // 获取 I/O 操作就绪的 SelectionKey, 通过 SelectionKey 可以知道哪些 Channel 的哪类 I/O 操作已经就绪.
            Iterator keyIterator = selector.selectedKeys().iterator();

            while (keyIterator.hasNext()) {

                SelectionKey key = keyIterator.next();

                // 当获取一个 SelectionKey 后, 就要将它删除, 表示我们已经对这个 IO 事件进行了处理.
                keyIterator.remove();

                if (key.isAcceptable()) {
                    // 当 OP_ACCEPT 事件到来时, 我们就有从 ServerSocketChannel 中获取一个 SocketChannel,
                    // 代表客户端的连接
                    // 注意, 在 OP_ACCEPT 事件中, 从 key.channel() 返回的 Channel 是 ServerSocketChannel.
                    // 而在 OP_WRITE 和 OP_READ 中, 从 key.channel() 返回的是 SocketChannel.
                    SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
                    clientChannel.configureBlocking(false);
                    //在 OP_ACCEPT 到来时, 再将这个 Channel 的 OP_READ 注册到 Selector 中.
                    // 注意, 这里我们如果没有设置 OP_READ 的话, 即 interest set 仍然是 OP_CONNECT 的话, 那么 select 方法会一直直接返回.
                    clientChannel.register(key.selector(), OP_READ, ByteBuffer.allocate(BUF_SIZE));
                }

                if (key.isReadable()) {
                    SocketChannel clientChannel = (SocketChannel) key.channel();
                    ByteBuffer buf = (ByteBuffer) key.attachment();
                    long bytesRead = clientChannel.read(buf);
                    if (bytesRead == -1) {
                        clientChannel.close();
                    } else if (bytesRead > 0) {
                        key.interestOps(OP_READ | SelectionKey.OP_WRITE);
                        System.out.println("Get data length: " + bytesRead);
                    }
                }

                if (key.isValid() && key.isWritable()) {
                    ByteBuffer buf = (ByteBuffer) key.attachment();
                    buf.flip();
                    SocketChannel clientChannel = (SocketChannel) key.channel();

                    clientChannel.write(buf);

                    if (!buf.hasRemaining()) {
                        key.interestOps(OP_READ);
                    }
                    buf.compact();
                }
            }
        }
    }
}


Netty NioServer

NioServerSocketChannel

NioServerSocketChannel
  • NioServerSocketChannel的类继承关系如上图,核心关注NioServerSocketChannel和AbstraceNioChannel。
  • NioServerSocketChannel和AbstraceNioChannel类关注初始化顺序。


public class NioServerSocketChannel extends AbstractNioMessageChannel
                             implements io.netty.channel.socket.ServerSocketChannel {

    private static final ChannelMetadata METADATA = new ChannelMetadata(false, 16);
    // SelectorProvider.provider()返回的是单例对象
    private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
    private final ServerSocketChannelConfig config;

    private static ServerSocketChannel newSocket(SelectorProvider provider) {
        try {
            return provider.openServerSocketChannel();
        } catch (IOException e) {
        }
    }

    public NioServerSocketChannel() {
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }

    public NioServerSocketChannel(ServerSocketChannel channel) {
        super(null, channel, SelectionKey.OP_ACCEPT);
        config = new NioServerSocketChannelConfig(this, javaChannel().socket());
    }
}
 


public abstract class AbstractNioChannel extends AbstractChannel {

    private final SelectableChannel ch;
    protected final int readInterestOp;
    volatile SelectionKey selectionKey;

    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent);
        this.ch = ch;
        this.readInterestOp = readInterestOp;
        try {
            // 如果一个Channel要注册到Selector中, 那么这个Channel必须是非阻塞的
            // 即channel.configureBlocking(false);
            ch.configureBlocking(false);
        } catch (IOException e) {
        }
    }

    protected SelectableChannel javaChannel() {
        return ch;
    }
}
  • NioServerSocketChannel核心关注SelectableChannel和readInterestOp。
  • DEFAULT_SELECTOR_PROVIDER是通过SelectorProvider.provider()返回单例对象。
  • SelectableChannel对象由provider.openServerSocketChannel()。
  • readInterestOp在NioServerSocketChannel中监听事件为SelectionKey.OP_ACCEPT。
  • 核心关注ServerSocketChannel,继续关注分析。
  • 核心关注SelectorProvider,用于创建ServerSocketChannel对象,继续关注分析。


ServerSocketChannel

ServerSocketChannel
  • ServerSocketChannel的类关系图如上图所示,突出父类SelectableChannel,解答AbstractNioChannel的参数对象SelectableChannel的缘由。


SelectorProvider

SelectorProvider
  • SelectorProvider的类图如上所示,生成ServerSocketChannel对象,分析下原理。


public abstract class SelectorProvider {

    private static final Object lock = new Object();
    private static SelectorProvider provider = null;

    public static SelectorProvider provider() {
        synchronized (lock) {
            if (provider != null)
                return provider;
            return AccessController.doPrivileged(
                new PrivilegedAction() {
                    public SelectorProvider run() {
                            if (loadProviderFromProperty())
                                return provider;
                            if (loadProviderAsService())
                                return provider;
                            provider = sun.nio.ch.DefaultSelectorProvider.create();
                            return provider;
                        }
                    });
        }
    }
}


public abstract class SelectorProviderImpl extends SelectorProvider {

    public abstract AbstractSelector openSelector() throws IOException;

    public ServerSocketChannel openServerSocketChannel() throws IOException {
        return new ServerSocketChannelImpl(this);
    }

    public SocketChannel openSocketChannel() throws IOException {
        return new SocketChannelImpl(this);
    }
}
  • SelectorProvider#provider用于生成单例的SelectorProvider对象。
  • SelectorProviderImpl#openServerSocketChannel负责创建ServerSocketChannel对象。
  • SelectorProviderImpl#openSocketChannel负责创建SocketChannel对象。
  • 在Netty的体系里面channel对象都是由SelectorProvider来完成的,相当于灵魂。


register分析

注册调用链
  • channel注册调用链如上图,按照NioEventLoopGroup => NioEventLoop => NioSocketChannel进行注册。
  • 最终的注册是将NioSocketChannel注册到NioEventLoop的selector对象当中。


NioEventLoopGroup注册

public abstract class AbstractBootstrap, C extends Channel> implements Cloneable {

    final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
            channel = channelFactory.newChannel();
            init(channel);
        } catch (Throwable t) {
        }
        // 进入NioEventLoopGroup的register过程,进入NioEventLoop的过程
        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }

        return regFuture;
    }
}

public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {

    public ChannelFuture register(Channel channel) {
        return next().register(channel);
    }
}
  • config().group().register(channel)的方法中从NioEventLoopGroup执行register方法。
  • next().register(channel)的方法实现从NioEventLoopGroup到NioEventLoop的调用传递。


NioEventLoop注册

public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {

    public ChannelFuture register(Channel channel) {
        // DefaultChannelPromise(channel, this)的this为NioEventLoop对象
        return register(new DefaultChannelPromise(channel, this));
    }

    public ChannelFuture register(final ChannelPromise promise) {

        ObjectUtil.checkNotNull(promise, "promise");
        // 由NioEventLoop进入NioSocketChannel的register过程
        promise.channel().unsafe().register(this, promise);
        return promise;
    }
}
  • promise.channel().unsafe().register(this, promise)实现由NioEventLoop到NioSocketChannel的调用传递。


NioSocketChannel注册

public abstract class AbstractNioChannel extends AbstractChannel {

    protected abstract class AbstractUnsafe implements Unsafe {
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            AbstractChannel.this.eventLoop = eventLoop;

            if (eventLoop.inEventLoop()) {
                register0(promise);
            } else {
                try {
                    eventLoop.execute(new Runnable() {
                        @Override
                        public void run() {
                            register0(promise);
                        }
                    });
                } catch (Throwable t) {
                }
            }
        }

        private void register0(ChannelPromise promise) {
            try {
                // 省略代码
                doRegister();
            } catch (Throwable t) {
            }
        }

    }

    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
                // 绑定NioSocketChannel到NioEventLoop对象当中,并且附加NioSocketChannel对象。
                selectionKey = javaChannel().register(eventLoop().selector, 0, this);
                return;
            } catch (CancelledKeyException e) {
            }
        }
    }
}
  • AbstractUnsafe#register执行的NioSocketChannel的注册动作,最终会执行AbstractNioChannel#doRegister。
  • AbstractNioChannel#doRegister内部通过javaChannel().register(eventLoop().selector, 0, this)实现绑定Channel到NioEventLoop对象当中。

你可能感兴趣的:(netty源码分析 - register分析)