Netty学习笔记_10(Netty核心模块组件)

1、BootStrap,ServerBootStrap

  1. 一个Netty应用通常由一个BootStrap开始,主要作用是配置整个Netty程序,串联各个组件,Netty中的BootStrap类是客户端程序的启动引导类,ServerBootStrap是服务端启动引导类
  2. 常见方法:

    public ServerBootstrap group  (EventLoopGroup parentGroup,

    EventLoopGroup childGroup)

    作用于服务器端,用来设置两个EventLoop

    public B group(EventLoopGroup group)

    作用于客户端,用来设置一个EventLoopGroup

    public B channel(Class<? extends C> channelClass)

    用来设置一个服务端的通道实现

    public <T> B option(ChannelOption<T> option, T value)

    用来给ServerChannel添加配置

    Public <T> ServerBootStrap childOption  (ChannelOption<T> childOption, T value)

    用来给接收到的通道添加配置

    public ServerBootstrap childHandler (ChannelHandler childHandler)

    用来设置业务处理类(自定义handler)

    childHandler主要针对于服务器端为客户端划分;

    public B handler(ChannelHandler handler)

    Handler则在服务器端本身发挥作用

    public ChannelFuture bind(int inetPort)

    用于服务器,设置占用的端口号

    public ChannelFuture connect (String inetHost,int inetPort)

    该方法用于客户端,用来连接服务器

 2、Future,ChannelFuture

  1. Netty中所有操作都是异步的,不能立即得知消息是否被正确处理,但可以过一会等它执行完成或直接注册一个监听器,具体实现通过Future和ChannelFuture,它们可以注册一个监听,当操作执行成功或失败时,监听会自动触发注册的监听事件
  2. 常用方法:

    Channel channel()

    返回当前正在进行IO操作的通道

    ChannelFuture sync()

    等待异步操作执行完毕

 3、Channel

  1. Channel是Netty网络通信组件,能够用于执行网络IO操作
  2. 通过Channel可获得当前网络连接的通道状态
  3. 通过Channel可获得网络连接配置参数
  4. Channel提供异步的网络IO操作(建立连接,读写,绑定端口),异步调用意味着任何IO调用都将立即返回,但不保证在调用结束时所请求的IO操作已完成
  5. 调用立即返回一个ChannelFuture实例,通过注册监听器,可以在IO操作成功、失败或取消时回调通知调用方
  6. 支持关联IO操作与对应的处理程序
  7. 不同协议、不同的阻塞类型的连接是不同的,Channel类型与之对应,常用的Channel类型有:

    NioSocketChannel

    异步的客户端TCP socket连接

    NioServerSocketChannel

    异步的服务器TCP socket连接

    NioDatagramChannel

    异步的UDP连接

    NioSctpChannel

    异步的客户端Sctp连接

    NioSctpServerChannel

    异步的服务端Sctp连接

 4、Selector

  1. Netty基于Selector对象实现IO多路复用,通过Selector一个线程可以监听多个连接的Channel事件
  2. 当向一个Selector中注册Channel后,Selector内部的机制就可以自动不断地查询(select)这些Channel中是否有就绪的IO事件(可读、可写、完成网络连接等),这样程序就可以简单地使用一个线程高效地管理多个Channel

5、ChannelHandler及其实现类

  1. ChannelHandler是一个接口,处理IO事件 / 拦截IO操作,并将其转发到其ChannelPipeline(业务处理链)中的下一个处理程序
  2. ChannelHandler本身并没有提供很多方法,因为这个接口有许多方法需要实现,方便使用的时候,可以继承它的子类
  3. ChannelHandler及其实现类:

                                                                     接           口

    ChannelInboundHandler 用于处理Channel(通道)入站IO事件;
    ChannelOutboundHandler 用于处理Channel(通道)出站IO事件;
                                                            适             配              器
    ChannelOutboundHandlerAdapter 用于处理出站IO操作;
    ChanneInboundHandlerAdapter 用于处理入站IO操作;
    ChannelDuplexHandler 用于处理入站和出站事件。

Netty学习笔记_10(Netty核心模块组件)

【注】以客户端应用程序为例:如果事件运动方向客户端服务器,我们称之为“出站”,即客户端发送的数据会通过pipeline中的一系列ChannelOutboundHandler,并被这些Handler处理,反之称为“入站”。

        4、自定义handler类继承ChannelInboundHandlerAdapter,通过重写相应方法实现业务逻辑:

public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {

 

               public void channelRegistered(ChannelHandlerContext ctx) throws Exception {

                             ctx.fireChannelRegistered();

               }

                public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {

                              ctx.fireChannelUnregistered();

                }

               //通道就绪事件

                public void channelActive(ChannelHandlerContext ctx) throws Exception {

                              ctx.fireChannelActive();

                }

               public void channelInactive(ChannelHandlerContext ctx) throws Exception {

                              ctx.fireChannelInactive();

                }

                  //通道读取数据事件

                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

                              ctx.fireChannelRead(msg);

                }

              //读取数据完毕

               public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

                              ctx.fireChannelReadComplete();

                }

                public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {

                               ctx.fireUserEventTriggered(evt);

               }

               public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {

                              ctx.fireChannelWritabilityChanged();

               }

               //异常捕获事件

               public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)   throws Exception {

                             ctx.fireExceptionCaught(cause);

                }

}

6、Pipeline和ChannelPipeline

  1. ChannelPipeline是一个handler的集合,负责处理和拦截inbound / outbound的事件或操作。ChannelPipeline是ChannelHandler实例对象的链表
  2. ChannelPipeline实现了一种高级形式的拦截过滤器模式,用户可以完全控制事件的处理方式,以及Channel中各个ChannelHandler的交互模式
  3. 一个Channel包含了一个ChannelPipeline,而一个ChannelPipeline中又维护了一个由ChannelHandlerContext组成的双向链表,且每个ChannelHandlerContext中由关联了一个ChannelHandler;
  4. 入站事件和出站事件在一个双向链表中,入站事件会从链表head往后传递到最后一个入站的handler,出站事件会从链表tail往前传递到第一个出站的handler,两者互不干扰。

    ...

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {

                      ChannelPipeline pipeline = ch.pipeline();

                     pipeline.addLast("MyHttpServerCC",new HttpServerCodec());
                    //增加一个自定义的处理器
                    pipeline.addLast("MyHttpServerHandler",new TestHttpServerHandler());

    断点        System.out.println("ok");
    }

    ...

    这段代码中显然有两个handler对象HttpServerCodec()和TestHttpServerHandler(),通过debug来观察ChannelPipeline构成的双向链表:

    显然,pipeline 对象中包含了一个head和tail,从head中进入,可以看到链表第一个元素为我们编写的初始化文件TestServerInitializer,它本质上也是一个自定义的handler;

    而next(下一个)即为HttpServerCodec

    继续next,发现下一个handler为TestHttpServerHandler

    继续next,得到链表尾元素,即默认的DefultChannelPipeline$TailContext,其中不再包含handler;

    反向从tail进入,可以发现末尾元素没有handler,且next属性为null,prev指向它的前一个handler,即TestHttpServerHandler;

    TestHttpServerHandlerprev指向前一个handler,即HttpServerCodec

    HttpServerCodec的前一个handler则是链表中第一个元素,即TestServerInitializer。

    【注】在TestHttpServerHandler中传入的ctx,本质上是DefaultChannelHandlerContext类型的数据

  5. 常用方法:

    ChannelPipeline addFirst(String name, ChannelHandler handler);

    把一个业务处理类(handler)添加到链表中第一个位置

    ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler);

    把一个业务处理类(handler)添加到链表中最后一个位置