本文主要讲解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里面设置的是什么值?
在启动bootstarp的时候,会设置一个NioServerSocketChannel,这里就是将这个类,放入channelFactory中
所以当调用
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());
}
一直点击父类的创建,最终会调用
在channel创建的时候,会创建unsage类和pipline,这两个类的作用,后面会专门写文章讲述
二.初始化服务端channel
调用init(channel)方法,初始化channel;
在创建完NioServerSocketChannel后,接下来就对该chanel进行初始化,做了三件事情
- 设置options
- 设置attrs
- NioServerSocketChannel添ServerBootstrapAcceptor的handler 依次展开
1.设置options
如上图,取出配置类设置的options,存入channelConfig类的options
2.设置attrs
同理,取出配置类设置的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()方法
来到我们最核心的,底层就是调用JDK的channel的register方法,把这个channel注册到这个selector上,同时关注事件是0(不关注任何事件)
注意:这里关注的事件是0,后面当这个channle激活后,会重新设置关注的事件是OP_ACCEPT