netty源码分析(二):服务端启动

103 阅读4分钟

本文主要讲解netty服务端启动,主要分三部分

  • 1.创建服务端channel
  • 2.初始化服务端channel
  • 3注册selector

在讲解之前,还是粘贴netty服务端启动的模板代码

public class MyServer {

    public static void main(String[] args) {
        // 1.构建 bossGroup 和 workGroup
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workGroup = new NioEventLoopGroup(1);

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // 2.设置group
        serverBootstrap.group(bossGroup, workGroup);
        // 3.设置服务端option和attr
        serverBootstrap.option(ChannelOption.SO_BACKLOG, 1);
        serverBootstrap.attr(AttributeKey.valueOf("name"),"彭青松");
        // 4.设置服务端的channel
        serverBootstrap.channel(NioServerSocketChannel.class);
        // 5.设置服务端的handler
        serverBootstrap.handler(new MyServerHandler());
        // 6.设置客户端的handler
        serverBootstrap.childHandler(new ChannelInitializer() {
            @Override
            protected void initChannel(Channel ch) throws Exception {
                // 7.客户端channel初始化的时候,调用这里
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new MyTcpClinetHandler());
            }
        });

        try {
            // 8.服务绑定端口,启动
            ChannelFuture channelFuture = serverBootstrap.bind(8888).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}

接下来进入服务端启动入口

 serverBootstrap.bind(8888)

会进入到

private ChannelFuture doBind(final SocketAddress localAddress) {
    // 1.这里创建并初始化服务端channel
    final ChannelFuture regFuture = initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
        return regFuture;
    }

    if (regFuture.isDone()) {
        // At this point we know that the registration was complete and successful.
        ChannelPromise promise = channel.newPromise();
        doBind0(regFuture, channel, localAddress, promise);
        return promise;
    } else {
        // Registration future is almost always fulfilled already, but just in case it's not.
        final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
        regFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                Throwable cause = future.cause();
                if (cause != null) {
                    // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
                    // IllegalStateException once we try to access the EventLoop of the Channel.
                    promise.setFailure(cause);
                } else {
                    // Registration was successful, so set the correct executor to use.
                    // See https://github.com/netty/netty/issues/2586
                    promise.registered();

                    doBind0(regFuture, channel, localAddress, promise);
                }
            }
        });
        return promise;
    }
}

一.创建服务端channel

initAndRegister()进创建和初始化
final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        //1.通过channelFactory反射创建NioServerSocketChannle
        channel = channelFactory.newChannel();
        //2.对创建出来的NioServerSocketChannle
        init(channel);
    } catch (Throwable t) {
        if (channel != null) {
            channel.unsafe().closeForcibly();
        }
        return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
    }

    ChannelFuture regFuture = config().group().register(channel);
    if (regFuture.cause() != null) {
        if (channel.isRegistered()) {
            channel.close();
        } else {
            channel.unsafe().closeForcibly();
        }
    }
    return regFuture;
}

调用channelFactory.newChannel()方法创建channel;

首先我们要知道channelFactory里面设置的是什么值?

image.png 在启动bootstarp的时候,会设置一个NioServerSocketChannel,这里就是将这个类,放入channelFactory中

image.png 所以当调用

channelFactory.newChannel()的时候,实际就是通过反射闯将NioServerSocketChannel

NioServerSocketChannel的创建

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

再次进入

public NioServerSocketChannel(ServerSocketChannel channel) {
    // 注意这里关注的事件是OP_ACCEPT
    super(null, channel, SelectionKey.OP_ACCEPT);
      // 每一个channel都有一个config,用于配置该channel
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}

一直点击父类的创建,最终会调用

image.png 在channel创建的时候,会创建unsage类和pipline,这两个类的作用,后面会专门写文章讲述

二.初始化服务端channel

调用init(channel)方法,初始化channel;

在创建完NioServerSocketChannel后,接下来就对该chanel进行初始化,做了三件事情

  • 设置options
  • 设置attrs
  • NioServerSocketChannel添ServerBootstrapAcceptor的handler 依次展开

1.设置options

image.png 如上图,取出配置类设置的options,存入channelConfig类的options

2.设置attrs

image.png 同理,取出配置类设置的attrs,存入channelConfig类的attrs 注意: options存储的是tcp的一些参数,attrs存储一般是我们自定义的参数

3. 添加连接器的handler

ch.eventLoop().execute(new Runnable() {
  @Override
  public void run() {
      pipeline.addLast(new ServerBootstrapAcceptor(
              currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
  }
});

这四个参数

  • currentChildGroup :启动类中的workGroup

  • currentChildHandler: 启动类中设置的childHandler

  • currentChildOptions: 启动类中设置的childOptinos

  • currentChildAttrs: 启动类中设置的childAttr

三.注册selector

概要: 将前面创建并初始化的channel,注册到bossGroup中的一个EventLoop中的selector上

ChannelFuture regFuture = config().group().register(channel);

点击进入

@Override
public ChannelFuture register(Channel channel) {
    return next().register(channel);
}
next()方法,会从bossGroup中会轮训的选择一个EventLoop,由于我们在创建bossGroup中,只设置一个EventLoop,所以一直选出来这个唯一的EventLoop,继续点击进入register(channel)方法
@Override
public ChannelFuture register(Channel channel) {
//会将channel和EventLoop封装成DefaultChannelPromise,进行注册
    return register(new DefaultChannelPromise(channel, this));
}

继续进入

@Override
public ChannelFuture register(final ChannelPromise promise) {
    ObjectUtil.checkNotNull(promise, "promise");
    // 会调用channel中的unsafe类进行注册
    promise.channel().unsafe().register(this, promise);
    return promise;
}

继续进入

private void register0(ChannelPromise promise) {
    try {
        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();
            }
        }
    } catch (Throwable t) {
        closeForcibly();
        closeFuture.setClosed();
        safeSetFailure(promise, t);
    }
}

继续进入doRegister()方法

image.png 来到我们最核心的,底层就是调用JDK的channel的register方法,把这个channel注册到这个selector上,同时关注事件是0(不关注任何事件)

注意:这里关注的事件是0,后面当这个channle激活后,会重新设置关注的事件是OP_ACCEPT

总结:本章主要讲解netty的服务端启动过程中的三个核心流程,其他细节会在后面逐步讲解,谢谢大家.