您当前的位置: 首页 >  服务器

庄小焱

暂无认证

  • 2浏览

    0关注

    805博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Netty——服务器启动ChannelFuture源码分析

庄小焱 发布时间:2021-11-09 18:49:59 ,浏览量:2

摘要

本博文主要分析服务器的启动的源码,主要分析ChannelFuture f = b.bind(8888).sync()原理。

服务器启动代码
/**
 * Created by chenhao on 2019/9/4.
 */
public final class SimpleServer {

    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new SimpleServerHandler())
                    .childHandler(new SimpleServerInitializer())
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(8888).sync();

            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
ChannelFuture f = b.bind(8888).sync() AbstractBootstrap.java
public ChannelFuture bind(int inetPort) {
    return bind(new InetSocketAddress(inetPort));
}
public ChannelFuture bind(SocketAddress localAddress) {
    validate();
    //相关参数的检查
    if (localAddress == null) {
        throw new NullPointerException("localAddress");
    }
    //绑定方法
    return doBind(localAddress);
}
validate()方法
//函数功能:检查相关参数是否设置了
@SuppressWarnings("unchecked")
public B validate() {
    //这里的group指的是:b.group(bossGroup, workerGroup)代码中的bossGroup
    if (group == null) {
        throw new IllegalStateException("group not set");
    }

    if (channelFactory == null) {
        throw new IllegalStateException("channel or channelFactory not set");
    }
    return (B) this;
}

该方法主要检查了两个参数,一个是group,一个是channelFactory,在这里可以想一想这两个参数是在哪里以及何时被赋值的?答案是在如下代码块中被赋值的,其中是将bossGroup赋值给了group,将BootstrapChannelFactory赋值给了channelFactory。

ServerBootstrap b = new ServerBootstrap();
                b.group(bossGroup, workerGroup)
                 .channel(NioServerSocketChannel.class)
doBind(localAddress)方法
private ChannelFuture doBind(final SocketAddress localAddress) {
    final ChannelFuture regFuture = initAndRegister();//1
    final Channel channel = regFuture.channel();//2
    if (regFuture.cause() != null) {
        return regFuture;
    }

    final ChannelPromise promise;
    if (regFuture.isDone()) {
        promise = channel.newPromise();
        doBind0(regFuture, channel, localAddress, promise);
    } else {
        // Registration future is almost always fulfilled already, but just in case it's not.
        promise = new PendingRegistrationPromise(channel);
        regFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                doBind0(regFuture, channel, localAddress, promise);
            }
        });
    }

    return promise;
}

doBind这个函数是我们要分析的重点,这个函数的主要工作有如下几点:

  • 1、通过initAndRegister()方法得到一个ChannelFuture的实例regFuture。
  • 2、通过regFuture.cause()方法判断是否在执行initAndRegister方法时产生来异常。如果产生来异常,则直接返回,如果没有产生异常则进行第3步。
  • 3、通过regFuture.isDone()来判断initAndRegister方法是否执行完毕,如果执行完毕来返回true,然后调用doBind0进行socket绑定。如果没有执行完毕则返回false进行第4步。
  • 4、regFuture会添加一个ChannelFutureListener监听,当initAndRegister执行完成时,调用operationComplete方法并执行doBind0进行socket绑定。

第3、4点想干的事就是一个:调用doBind0方法进行socket绑定。

initAndRegister()
final ChannelFuture initAndRegister() {
    //结论:这里的channel为一个NioServerSocketChannel对象,具体分析见后面
    final Channel channel = channelFactory().newChannel();//1
    try {
        init(channel);//2
    } catch (Throwable t) {
        channel.unsafe().closeForcibly();
        // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
        return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
    }

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

通过函数名以及内部调用的函数可以猜测该函数干了两件事情:

1、初始化一个Channel,要想初始化,肯定要先得到一个Channel。

final Channel channel = channelFactory().newChannel();//1
init(channel);//2

2、将Channel进行注册。

ChannelFuture regFuture = group().register(channel);//3
final Channel channel = channelFactory().newChannel();

我们知道b.channel(NioServerSocketChannel.class)的功能为:设置父类属性channelFactory 为: BootstrapChannelFactory类的对象。其中这里BootstrapChannelFactory对象中包括一个clazz属性为:NioServerSocketChannel.class

因此,final Channel channel = channelFactory().newChannel();就是调用的BootstrapChannelFactory类中的newChannel()方法,该方法的具体内容为:

private static final class BootstrapChannelFactory implements ChannelFactory {
    private final Class            
关注
打赏
1657692713
查看更多评论
0.0999s