导读
原创文章,转载请注明出处。
本文源码地址:netty-source-code-analysis
本文所使用的netty版本4.1.6.Final:带注释的netty源码
我们在“BIO vs NIO”这篇文章中我们给出了使用jdk原生nio编写的服务端Hello World。还记得其中的关键步骤吗,咱们再来温习一下。
-
创建一个ServerSocketChannel
-
将ServerSocketChannel设置为非阻塞的
-
将ServerSocketChannel绑定到8000端口
-
将ServerSocketChannel注册到selector上
今天我们就以这几个关键步骤为目标来看一下在netty中是怎么做的,以及在这几个步骤的中间netty又多做了哪些工作。
1 服务端引导代码
以下代码引导启动一个服务端,在以下文章中我们以“引导代码”指代这段程序。这段代码很简单,创建两个EventLoopGroup
分别为bossGroup
和workerGroup
。创建一个ServerBoostrap
并将bossGroup
和workerGroup
传入,配置一个handler
,该handler
为监听端口这条连接所使用的handler
。接着又设置了一个childHandler
即新连接所使用的handler
,本篇文章我们不讲新连接的接入,所以这里的childHandler
里什么也没做。
运行这段这段代码将在控制台打出如下结果。
HandlerAdded
ChannelRegistered
ChannelActive
/**
* 欢迎关注公众号“种代码“,获取博主微信深入交流
*
* @author wangjianxin
*/
public class com.zhongdaima.netty.analysis.bootstrap.ServerBoot {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(1);
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.attr(AttributeKey.valueOf("ChannelName"), "ServerChannel")
.handler(new ChannelInboundHandlerAdapter() {
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("ChannelRegistered");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("ChannelActive");
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("HandlerAdded");
}
}).childHandler(new ChannelInboundHandlerAdapter(){
});
ChannelFuture f = b.bind(8000).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2 启动过程
我们从ChannelFuture f = b.bind(8000).sync()
的bind
方法往下跟到AbstractBootStrap
的doBind
方法,这中间的过程很简单,就是将端口号封装为SocketAddress
。
在doBind
内的关键代码有第一行的initAddRegister
方法,还有后面的doBind0
方法。
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
if (regFuture.isDone()) {
doBind0(regFuture, channel, localAddress, promise);
} else {
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) {
} else {
doBind0(regFuture, channel, localAddress, promise);
}
}