Netty服务端是如何一点一点被带动起来的(概略)

2022-06-02 14:13:05 浏览数 (1)

代码语言:javascript复制
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个过程完成之后, 服务端也就启动起来了.

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

代码语言:javascript复制
EventLoopGroup bossGroup = new NioEventLoopGroup(1);

被创建的.

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

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

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

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

id,unsafe,pipeline,config等.

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

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

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

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

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

目前阶段会形成如下结构

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

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

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

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

0 人点赞