Netty入门 - Netty启动过程源码分析

Netty入门 - Netty启动过程源码分析

Netty 是一个高性能、异步事件驱动的网络应用框架,适用于快速开发可维护的协议服务器和客户端。理解 Netty 的启动过程有助于更好地掌握其工作原理和使用方法。本文将通过源码分析,介绍 Netty 的启动过程。

1. Bootstrap 类

Netty 的启动过程主要由 BootstrapServerBootstrap 类负责,分别用于客户端和服务器端的启动。我们先从 ServerBootstrap 类开始分析服务器的启动过程。

1.1 初始化 ServerBootstrap
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup, workerGroup)
     .channel(NioServerSocketChannel.class)
     .childHandler(new ChannelInitializer<SocketChannel>() {
         @Override
         public void initChannel(SocketChannel ch) throws Exception {
             ch.pipeline().addLast(new HelloServerHandler());
         }
     });

    ChannelFuture f = b.bind(8080).sync();
    f.channel().closeFuture().sync();
} finally {
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
}

2. ServerBootstrap 配置

2.1 group()

group 方法配置了两个线程组,一个 bossGroup 用于接受连接,另一个 workerGroup 用于处理已经被接受的连接的流量。

public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
    super.group(parentGroup);
    if (childGroup == null) {
        throw new NullPointerException("childGroup");
    }
    if (this.childGroup != null) {
        throw new IllegalStateException("childGroup set already");
    }
    this.childGroup = childGroup;
    return this;
}
2.2 channel()

channel 方法指定了服务器通道类型为 NioServerSocketChannel,它是一个使用 NIO 的服务器实现。

public B channel(Class<? extends C> channelClass) {
    return channelFactory(new ReflectiveChannelFactory<C>(ObjectUtil.checkNotNull(channelClass, "channelClass")));
}
2.3 childHandler()

childHandler 方法配置了 ChannelInitializer,用于设置 ChannelPipeline 以处理新的客户端连接。

public ServerBootstrap childHandler(ChannelHandler childHandler) {
    if (childHandler == null) {
        throw new NullPointerException("childHandler");
    }
    this.childHandler = childHandler;
    return this;
}

3. 绑定端口并启动

3.1 bind()

bind 方法用于绑定服务器到指定端口,并启动监听。

public ChannelFuture bind(int inetPort) {
    return bind(new InetSocketAddress(inetPort));
}

public ChannelFuture bind(SocketAddress localAddress) {
    validate();
    return doBind(localAddress);
}

private ChannelFuture doBind(final SocketAddress localAddress) {
    final ChannelFuture regFuture = initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
        return regFuture;
    }

    final ChannelPromise promise = channel.newPromise();
    if (regFuture.isDone()) {
        doBind0(regFuture, channel, localAddress, promise);
    } else {
        regFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                doBind0(regFuture, channel, localAddress, promise);
            }
        });
    }

    return promise;
}

private static void doBind0(
        final ChannelFuture regFuture, final Channel channel,
        final SocketAddress localAddress, final ChannelPromise promise) {

    channel.eventLoop().execute(new Runnable() {
        @Override
        public void run() {
            if (regFuture.isSuccess()) {
                channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            } else {
                promise.setFailure(regFuture.cause());
            }
        }
    });
}

4. 初始化和注册

4.1 initAndRegister()

initAndRegister 方法用于初始化和注册通道。

final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        channel = channelFactory.newChannel();
        init(channel);
    } catch (Throwable t) {
        if (channel != null) {
            channel.unsafe().closeForcibly();
            return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
        }
        return new DefaultChannelPromise(new FailedChannel(), 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;
}

5. 处理客户端连接

当客户端连接到服务器时,ChannelInitializer 会被调用,初始化 ChannelPipeline,并添加自定义的 ChannelHandler 以处理 I/O 事件。

总结

Netty 的启动过程涉及一系列配置和初始化操作,包括配置线程组、通道类型、处理程序、绑定端口以及处理客户端连接。通过源码分析,我们可以更深入地理解 Netty 的工作原理和使用方式。掌握这些知识可以帮助我们更好地使用 Netty 开发高性能的网络应用。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值