12-高并发-netty原理和基础-基础原件+启动器

本文介绍了Netty中的出站和入站概念,详细阐述了Netty的基本流程,包括通道注册、查询选择、事件分发和IO操作。接着讨论了Netty中的channel组件、Reactor、Handler及其工作原理。还提到了netty的ChannelPipeline流水线设计,以及服务器端的启动流程,包括EventLoopGroup线程组的作用和配置建议。

Netty极大地简化了TCP、UDP套接字、HTTP web服务程序的开发。

一、出站和入站。

简单来说,出站就是指输出,入站就是指输入。

二、基本流程

Channel  -->   selector -->  Reactor ---> handler

  • 第1步:通道注册。IO源于通道(Channel)。IO是和通道(对应于底层连接而言)强相关的。一个IO事件,一定属于某个通道。但是,如果要查询通道的事件,首先要将通道注册到选择器。只需通道提前注册到Selector选择器即可,IO事件会被选择器查询到。
  • 第2步:查询选择。在反应器模式中,一个反应器(或者SubReactor子反应器)会负责一个线程;不断地轮询,查询选择器中的IO事件(选择键)。
  • 第3步:事件分发。如果查询到IO事件,则分发给与IO事件有绑定关系的Handler业务处理器。
  • 第4步:完成真正的IO操作和业务处理,这一步由Handler业务处理器负责。

以上4步,就是整个反应器模式的IO处理器流程。其中,第1步和第2步,其实是Java NIO的功能,反应器模式仅仅是利用了Java NIO的优势而已。

三、netty中的channel组件

四、netty中的反应器-Reactor

反应器模式中,一个反应器(或者SubReactor子反应器)会负责一个事件处理线程,不断地轮询,通过Selector选择器不断查询注册过的IO事件(选择键)。如果查询到IO事件,则分发给Handler业务处理器。

                   

 

netty的反应器为NIOEventLoop。通过关系图,可以看出:一个NioEventLoop拥有一个Thread线程,负责一个Java NIO Selector选择器的IO事件轮询。

五、netty中的处理器-Handler

  • 可供选择器监控的通道IO时间类型4中:可读-READ,可写-WRITE,连接-CONNECT,接收-ACCEPT
  • 选择器执行以上事件的查询,然后进行对应的事件分发,分发目标就是netty的Handler处理器。

六、netty的流水线

  • netty设计了一个特殊的组件-ChannelPipeline-通道流水线。实际设计为一个双向链表。
  • 入站的IO操作只会且只能从INbound入站处理器类型的Handler流过。出站的IO操作只会且只能从Outbound出站处理器类型的Handler流过。

七、启动器

bootstrap类是netty提供的一个便利的工厂类。用来快速组装通道、反应器、处理器。

父子通道:

  • 连接监听类型:放在服务端,负责接收客户端的套接字连接。ACCEPT。
  • 传输数据类型:放在客户端和服务端。
  • 在netty中,将有接收关系的NIOServerSocketChannel(父)和NIOSocketChannel(子)叫做父子通道。

EventLoopGroup线程组:

  • 在netty中,一个EventLoop相当于一个子反应器。一个EventLoop相当于一个线程。
  • netty的程序开发不用直接使用单个EventLoop线程,而是使用EventLoopGroup。默认的EventloopGroup内部线程数为CPU*2。
  • 为了及时接收到新连接。在服务器端,一般有两个独立的反应器,一个反应器负责连接的监听和接收,另一个反应器负责IO事件处理。对应到netty的服务器程序中,则是设置到两个EventLoopGroup线程组,一个EventLoopGroup负责新连接监听和接收---Boss线程组,一个EventLoopGroup负责IO事件处理,并执行Handler处理器中的业务处理---Worker线程组

启动流程

1.创建反应器线程组,并赋值给启动器实例。

注:不一定非得配置两个线程组,可以仅配置一个EventLoopGroup反应器线程组。具体的配置方法是调用b.group( workerGroup)。在这种模式下,连接监听IO事件和数据传输IO事件可能被挤在了同一个线程中处理。这样会带来一个风险:新连接的接受被更加耗时的数据传输或者业务处理所阻塞。
注:在服务器端,建议设置成两个线程组的工作模式。

           
            //创建反应器线程组
            //boss线程组
            EventLoopGroup  bossLoopGroup = new NioEventLoopGroup(1);
            //worker线程组
            EventLoopGroup  workerLoopGroup = new NioEventLoopGroup();
            //...
            //1 设置反应器线程组
            b.group(bossLoopGroup, workerLoopGroup);

2.设置通道的IO类型

                  //2 设置nio类型的通道
                  b.channel(NioServerSocketChannel.class);

3.设置监听端口

                  //3 设置监听端口
                  b.localAddress(new InetSocketAddress(port));

4.设置传输通道的配置选项

    注:option()设置父通道,childOption()设置子通道。

                  //4 设置通道的参数
                  b.option(ChannelOption.SO_KEEPALIVE, true);//是否开启心跳机制
                  b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);


通道参数:
SO_RCVBUF,SO_SNDBUF  
发送缓冲区和接收缓冲区。
TCP_NODELAY
立即发送数据。
SO_KEEOALIVE
心跳机制
SO_REUSEADDR
地址复用
SO_LINGER
关闭socket的延迟时间
SO_BACKLOG
服务器端接收连接的队列长度
SO_BROADCAST
设置广播模式

5.装配子通道的PiPeline流水线

  •  注:每一条通道的子通道,都用一条ChannelPipeline流水线。它的内部有一个双向的链表。
  •  注:父通道不需要装配流水线。他的内部业务固定:接收新连接,创建子通道,初始化子通道。
  •  注:ChannelInitializer有一泛型参数SocketChannel,代表初始化通道类型。这个类和启动器中设置的通道类型会一一对应
        //5 装配子通道流水线
        b.childHandler(new ChannelInitializer<SocketChannel>() {
            //有连接到达时会创建一个通道的子通道,并初始化
            protected void initChannel(SocketChannel ch) throws Exception {
              // 流水线管理子通道中的Handler业务处理器
                // 向子通道流水线添加一个Handler业务处理器
                ch.pipeline().addLast(new NettyDiscardHandler());
            }
        });

6.开始绑定服务器新连接的监听端口

注:在netty中,所有的IO操作都是异步执行的,IO操作会立刻返回。执行完有两种方式,一自我阻塞到异步任务Future完成。二为Future增加时间监听器。

        // 6 开始绑定端口,通过调用sync同步方法阻塞直到绑定成功
        ChannelFuturechannelFuture = b.bind().sync();
        Logger.info(" 服务器启动成功,监听端口: " +
        channelFuture.channel().localAddress());

7.自我阻塞,知道通道关闭。

注:当通道被关闭时,closeFuture实例的sync()方法返回。

        // 7 等待通道关闭
        // 自我阻塞,直到通道关闭的异步任务结束
        ChannelFuturecloseFuture = channelFuture.channel().closeFuture();
        closeFuture.sync();

8.关闭EventLoopGroup

注:关闭Reactor反应器线程组,同时会关闭内部的subReactor子反应器线程,也会关闭内部的Selector选择器、内部的轮询线程以及负责查询的所有的子通道。在子通道关闭后,会释放掉底层的资源,如TCP Socket文件描述符等。

        // 8关闭EventLoopGroup,
        // 释放掉所有资源,包括创建的反应器线程
        workerLoopGroup.shutdownGracefully();
        bossLoopGroup.shutdownGracefully();

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

良之才-小良

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值