Netty权威指南(三)

11 服务端创建

11.1 Netty服务端创建源码分析

11.1.1 Netty服务端创建时序图

Netty服务端创建时序图
  1. 创建ServerBootstrap实例。ServerBootstrap是Netty服务端的启动辅助类,它提供了一系列的方法用于设置服务端启动相关参数。
  2. 设置并绑定Reactor线程池,Netty的Reactor线程池是EventLoopGroup它实际就是EventLoop的数组。EventLoop的职责就是处理所有注册到本线程多路复用器Selector上的Channel,Selector的轮询操作由绑定EventLoop线程run方法驱动,在一个循环体内循环执行。EventLoop的职责不仅仅是处理网络I/O事件,用户自定义的Task的定时任务Tak也统一由EventLoop负责处理,实现线程模型统一。
  3. 设置并绑定服务端Channel。作为NIO服务端需要创建ServerSocketChannel,Netty对原生的NIo类库进行了封装,对应实现是NioServerSocketChannel。
public ServerBootstrap channel(Class<? extends ServerChannel> channelClass) {
    if (channelClass == null) {
        throw new NullPointerException("channelClass");
    } else {
        return this.channelFactory(new ServerBootstrap.ServerBootstrapChannelFactory(channelClass));
    }
}
  1. 链路建立的时候创建并初始化ChannelPipeline.ChannelPipeline并不是NIO服务端必须的,它本质就是一个负责处理网络事件的职责链,负责管理和执行ChannelHandler。网络事件以事件流的形式ChannelPipeline中流转,由ChannelPipeline根据ChannelHandler的执行策略调度ChannelHandler的执行。网络事件一般有:链路注册、链路激活、链路断开、接收请求、请求消息接收并处理完成、发送应答消息、链路异常、自定义事件。
  2. 初始化ChannelPipeline完成之后,添加并设置ChannelHandler。ChannelHandler是Netty提供给用户定制和扩展的关键接口。利用ChannelHandler用户可以完成大多数的功能定制。比如
    1. 系统编解码框架-BtyeToMessageCodec
    2. 通用基于长度的半包解码器-LengthFieldBasedFrameDecoder
    3. 码流日志打印-LoggingHandler
    4. SSL安全认证-SslHandler
    5. 链路空闲检测-IdleStateHandler
    6. 流量整形-ChannelTrafficShapingHandler
    7. Base64编解码-Base64Decoder和Base64Encoder

创建和添加ChannelHandler代码示例

.childHandler(new ChannelInitializer<SocketChannel>() {
    @Override
    public void initChannel(SocketChannel ch)
            throws IOException {
        ch.pipeline().addLast(
                new NettyMessageDecoder(1024 * 1024, 4, 4));
        ch.pipeline().addLast(new NettyMessageEncoder());
        ch.pipeline().addLast("readTimeoutHandler",
                new ReadTimeoutHandler(50));
        ch.pipeline().addLast(new LoginAuthRespHandler());
        ch.pipeline().addLast("HeartBeatHandler",
                new HeartBeatRespHandler());
    }
});
  1. 绑定并启动监听端口。在绑定监听端口之前系统会做一系列的初始化和检测工作,完成之后,会启动监听端口,并将ServerSocketChannel注册到Selector上监听客户端连接。
private ChannelFuture doBind(final SocketAddress localAddress) {
    final ChannelFuture regFuture = this.initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
        return regFuture;
    } else {
        final Object promise;
        if (regFuture.isDone()) {
            promise = channel.newPromise();
            doBind0(regFuture, channel, localAddress, (ChannelPromise)promise);
        } else {
            promise = new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE);
            regFuture.addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) throws Exception {
                    AbstractBootstrap.doBind0(regFuture, channel, localAddress, (ChannelPromise)promise);
                }
            });
        }

        return (ChannelFuture)promise;
    }
}
  1. Selector轮询。由Reactor线程NioeventLoop负责调度和执行Selector轮询操作,选择准备就绪到Channel集合。
  2. 当轮询到准备就绪的Channel之后,就由Reactor线程NioEventLoop执行ChannelPipeline的相应方法,最终调度并执行ChannelHandler。
  3. 执行Netty系统ChannelHandler和用户添加定制的ChannelHandler。ChannelPipeline根据网络事件类型,调度并执行ChannelHandler。
public ChannelHandlerContext fireChannelRead(Object msg) {
    DefaultChannelHandlerContext next = this.findContextInbound(64);
    next.invoker.invokeChannelRead(next, msg);
    return this;
}

11.1.2 Netty服务端创建源码分析

首先通过构造函数创建ServerBootstrap实例,随后,通常会创建两个EventLoopGroup。

EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();

NioEventLoopGroup实际就是Reactor线程池,负责调度和执行客户端的接入、网络读写事件的处理、用户自定义任务和定时任务的执行。通过ServerBootstrao的group方法将两个EventLoopGroup实例传入。

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

其中父NioEventLoopGroup被传入了父

一条小咸鱼