一、netty服务端代码
public class NettyServerExample {
public static void main(String[] args) {
//第一步1:定义两个eventLoopGroup
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
//第二步2-1:定义bootStrap
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
bootstrap.channel(NioServerSocketChannel.class);
//第二步2-2:定义bossGroup对应的handler
bootstrap.handler(new FinalChannelEventHandler());
//第二步2-3:定义workerGroup对应的handler
FinalChannelEventHandler finalChannelEventHandler = new FinalChannelEventHandler();
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch){
ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
ch.pipeline().addLast(new IdleStateHandler(0, 0, 5000, TimeUnit.MILLISECONDS));
ch.pipeline().addLast(finalChannelEventHandler);
}
});
//第三步3:绑定端口
bootstrap.bind(12345).syncUninterruptibly();
}
@ChannelHandler.Sharable
private static class FinalChannelEventHandler extends SimpleChannelInboundHandler<Object>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object data) {
String s = ((ByteBuf) data).toString(CharsetUtil.UTF_8);
ByteBuf message = Unpooled.buffer(s.length());
message.writeBytes(s.getBytes(StandardCharsets.UTF_8));
ctx.channel().writeAndFlush(message);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
System.out.println("final inactive...");
}
@Override
public void channelActive(ChannelHandlerContext ctx){
System.out.println("final active...");
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt){
System.out.println("trigger: " + evt);
}
}
}
二、EventGroup初始化
从类继承和实现上看,NioEventLoopGroup实现了一个类似线程池的功能,随着代码一路跟踪下来,我们着重来看下MultithreadEventExecutorGroup这类的构造方法
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args)
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
checkPositive(nThreads, "nThreads");
if (executor == null) {
//线程池,自定义线程生成FastThreadLocalThread
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//线程组,eventLoopGroup线程池组包含多个eventLoop线程池
children = new EventExecutor[nThreads];
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
//生成的每个eventLoop,相当于只有一个核心线程,Integer.MAX_VALUE队列的线程池
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}
for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}
chooser = chooserFactory.newChooser(children);
final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};
for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}
Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
}
四个入参:
1.线程数设置0则为当前cpu core * 2
2.设置默认值为ThreadPerTaskExecutor线程池,使用FastThreadLocalRunnable生成线程执行任务
3.选择NioEventLoop的策略,2的n次方 与,非2的n次方 求余
executors[idx.getAndIncrement() & executors.length - 1] 与运算速度快
executors[(int) Math.abs(idx.getAndIncrement() % executors.length)]
4.args中包含三块:1.Selector 2.选择策略(select.selctNow()) 3.线程池拒绝策略(默认大小是Integer.MAX_VALUE)
三、ServerBootStrap初始化
1.一个是bossGroup绑定的handler,绑定时端口时初始化一次(后面绑定讲解)
2.一个是workerGroup绑定的handler,每次新连接初始化一次
四、端口绑定
AbstractBootstrap的doBind方法
private ChannelFuture doBind(final SocketAddress localAddress) {
//初始化和注册,包装了nio的注册;异步处理
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;
}
}
AbstractBootstrap的initAndRegister
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
//反射初始化SelectorProvider.provider().openServerSocketChannel()
channel = channelFactory.newChannel();
//初始化
init(channel);
} catch (Throwable t) {
if (channel != null) {
// channel can be null if newChannel crashed (eg SocketException("too many open files"))
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);
}
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
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;
}
ServerBootstrap的init方法
void init(Channel channel) {
setChannelOptions(channel, newOptionsArray(), logger);
setAttributes(channel, newAttributesArray());
ChannelPipeline p = channel.pipeline();
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions = newOptionsArray(childOptions);
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = newAttributesArray(childAttrs);
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
//这个地方是之前绑定只初始化一次bossGroup的handler的
if (handler != null) {
pipeline.addLast(handler);
}
//客户端连接服务端成功后,服务端accept后新建一个socketChannel将读写注册到workGroup中,ServerBootstrapAcceptor这个类中处理
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
}
ServerBootstrapAcceptor的channelRead
public void channelRead(ChannelHandlerContext ctx, Object msg) {
//accept的socketChannel,后续注册读写事件
final Channel child = (Channel) msg;
//新连接的socketChannel中每次在pipeline中新增childHandler
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
setAttributes(child, childAttrs);
try {
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}
NioServerSocketChannel的doReadMessages,serverBootstrap初始化时指定的bootstrap.channel(NioServerSocketChannel.class)
接下来看AbstractBootstrap中的dobind0方法
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
// This method is invoked before channelRegistered() is triggered. Give user handlers a chance to set up
// the pipeline in its channelRegistered() implementation.
//bossGroup的eventLoop直接启动线程,只需要绑定一次
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (regFuture.isSuccess()) {
//javaChannel().bind(localAddress, config.getBacklog())进行绑定
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
二、总结
1.启动过程中会产生一些异步事件,比如register,bind等,根据eventLoop.inEventLoop()判断当前程序执行的线程和首个启动eventLoop保存在其中的线程是否一致。一致直接执行,不一致扔进这个方法通常用于判断当前线程是否可以直接执行某些操作,以避免线程切换带来的性能损失。
2.eventLoopGroup可以理解为线程池的一个组,每个连接socketChannel从中获取一个线程池eventLoop;其中,一个连接只能对应一个线程池,一个线程池可以处理多个连接;eventLoop是个单线程+队列(默认Integer.MAX_VALUE)+拒绝策略。
3.bossGroup线程池一般是1,workerGroup默认是cpu core*2;bossGroup监听连接事件,accept后立刻注册到workerGroup上;类似经典的reactor模型中的多线程模型。