Netty入门 - Netty启动过程源码分析
Netty 是一个高性能、异步事件驱动的网络应用框架,适用于快速开发可维护的协议服务器和客户端。理解 Netty 的启动过程有助于更好地掌握其工作原理和使用方法。本文将通过源码分析,介绍 Netty 的启动过程。
1. Bootstrap 类
Netty 的启动过程主要由 Bootstrap
和 ServerBootstrap
类负责,分别用于客户端和服务器端的启动。我们先从 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 开发高性能的网络应用。