Netty服务端是如何一点一点被带动起来的

2021-03-21  本文已影响0人  书唐瑞
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class Server {
    public static void main(String[] args) throws Exception {

        // 这个线程用于接收客户端的连接
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // 这4个线程用于处理IO读写
        EventLoopGroup workerGroup = new NioEventLoopGroup(8);
        // 这8个线程用于业务处理
        EventLoopGroup businessGroup = new NioEventLoopGroup(8);

        ServerBootstrap serverBootstrap = new ServerBootstrap();
        try {
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) {
                            ChannelPipeline channelPipeline = ch.pipeline();
                            channelPipeline.addLast(new StringEncoder());
                            channelPipeline.addLast(new StringDecoder());
                            channelPipeline.addLast(businessGroup, new ServerInHandler());
                        }
                    });
            // bind绑定
            ChannelFuture channelFuture = serverBootstrap.bind("127.0.0.1", 8080).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

以上代码虽不能作为真正的服务端生产代码, 麻雀虽小五脏俱全, 它足以可以说明本篇所要阐述的过程.

Netty服务端启动的导火索就从这个bind方法开始了.

首先要说明一点的是,NioServerSocketChannel它会经历创建-初始化-注册-绑定这4大过程.
NioEventLoop它会经历创建-启动-执行这3大过程.
这4+3=7个过程完成之后, 服务端也就启动起来了.

图片.png

在执行bind方法之前, NioEventLoop已经完成了创建. (已经执行过的使用绿色表示). 它是通过EventLoopGroup bossGroup = new NioEventLoopGroup(1)被创建的.

NioEventLoop要想启动起来, 是由NioServerSocketChannel在注册的时候被启动起来的.

在执行bind方法的过程中, 首先会来到第一个重要的地方, 那就是创建NioServerSocketChannel.

源码位置: io.netty.bootstrap.AbstractBootstrap#initAndRegister

图片.png

在创建的过程, 主要创建了以下几个属性

图片.png

id,unsafe,pipeline,config等.

接下来就是初始化操作,这里面有个比较重要的操作

图片.png 图片.png

到目前为止,内存里有以下几个主要类

图片.png

继续看重要的NioServerSocketChannel的注册功能

图片.png 图片.png 图片.png

这个时候, NioEventLoop里就有了一个与之绑定的唯一线程, 同时队列里面有个注册任务. Thread就会取出注册任务并执行.

这个注册任务会走到如下地方


图片.png 图片.png

目前阶段会形成如下结构

图片.png

注册完成之后,接下来就是绑定操作.

图片.png

总之一句话, 注册操作要在绑定操作之前, 绑定操作必须在后面.

图片.png

绑定完成之后,会'激活'NioServerSocketChannel的ACCEPT事件,就可以接收客户端的请求了.

最后的结构图,请再熟悉下

图片.png
上一篇下一篇

猜你喜欢

热点阅读