netty基础02_netty组件

netty主要包含下列组件:
    Bootstrap 和 ServerBootstrap    ->引导类,用来配置netty组件;
    Channel    ->socket
    EventLoop    ->  处理io事件的线程
    ChannelPipeline    ->保存处理过程需要用到的ChannelHandler和ChannelHandlerContext
    ChannelHandler    ->处理请求
    ChannelFuture    ->  监听异步操作是否成功
 
1.Bootstrap
引导类,用来做配置,比如配置如何处理消息;
包括两种:
    Bootstrap    -》作用于客户端;
    ServerBootstrap    -》作用于服务端;有两个EventLoopGroup,一个用来获取channel,另一个用来处理channel;      
    
 
2.Channel
通道是对java原生网络编程api的封装,其顶级接口是Channel;
以TCP编程为例 ,在java中,有两种方式:
    1】基于BIO,JDK1.4之前,我们通常使用java.net包中的ServerSocket和Socket来代表服务端和客户端。
    2】基于NIO,Jdk1.4引入nio编程之后,我们使用java.nio.channels包中的ServerSocketChannel和SocketChannel来代表服务端与客户端。
 
在Netty中,对java中的BIO、NIO编程api都进行了封装,分别:
    1】使用了OioServerSocketChannel,OioSocketChannel对java.net包中的ServerSocket与Socket进行了封装
    2】使用NioServerSocketChannel和NioSocketChannel对java.nio.channels包中的ServerSocketChannel和SocketChannel进行了封装。
 
3. EventLoop
EventLoop的主要作用是处理channel的IO操作。
    一个 EventLoopGroup 包含一个或者多个 EventLoop;
    一个 EventLoop 在它的生命周期内只和一个 Thread 绑定;
    所有由 EventLoop 处理的 I/O 事件都将在它专有的 Thread 上被处理;
    一个 Channel 在它的生命周期内只注册于一个 EventLoop;
    一个 EventLoop 可能会被分配给一个或多个 Channel;
 
线程安全:
    一个Channel只会绑定一个EventLoop,并且一个EvnetLoop只会绑定一个线程;
    所以不需要考虑线程线程安全的问题;
    因为一个Channel的生命周期中,其所有的io操作都是由同一个线程来执行的;
 
4. ChannelFuture 
Netty 中所有的 I/O 操作都是异步的;
因此一个操作可能不会立即返回;
所以我们需要一种用于在之后的某个时间点确定其结果的方法;
为此, Netty 提供了ChannelFuture 接口;
可以通过ChannelFuture的addListener()方法注册一个监听器ChannelFutureListener以便在某个操作完成时获得通知;
ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080));
future.addListener(new ChannelFutureListener() {
    @Override
    public void operationComplete(ChannelFuture channelFuture)
    throws Exception {
        if (channelFuture.isSuccess()) {
            System.out.println("Server bound");
        } else {
            System.err.println("Bind attempt failed");
            channelFuture.cause().printStackTrace();
        }
    }
} );
 
5.ChannelHandler、ChannelPipeline
1)管道和处理器
ChannelHandler用来处理消息;
ChannelHandler接口有两个子接口:
    ChannelInboundHandler    ->处理进站的消息
    ChannelOutboundHandler    ->处理出站的消息
 
 
多个ChannelHandler会在根据在引导类Bootstrap中的配置,按顺序保存在管道ChannelPipeline中;
对于进站的消息,会按从管道头部到尾部的顺序,被管道中每个ChannelInboundHandler处理;直到到达管道尾部为止;
对于出站数据(即调用write方法写出数据),按从管道尾部开始到管道头部的顺序,依次被每个ChannelOutboundHandler处理,直到管道头部时,封装成socket写出;
 
多个ChannelHandler构成handler链;
事件可以通过ChanneHandlerContext传递给下一个handler;
 
2)netty提供的处理器
pipeline中每个 ChannelHandler负责处理事件并转发到下一个handler;
因此在程序中需要编写事件处理器并配置到管道中;
为了简化开发,netty提供了一些默认的处理器适配器(也就是抽象类,实现了ChannelHandler接口的一些方法);
常用适配器:ChannelHandlerAdapter、ChannelInboundHandlerAdapter、ChannelOutboundHandlerAdapter、ChannelDuplexHandlerAdapter    
 
常用的适配器子类:
1】编码器、解码器
解码:收到消息时,需要将二进制字节转换成java对象;
编码:响应时,将java对象转成二进制字节;
常用的编码器/解码器: ByteToMessageDecoder、MessageToByteEncoder
所有的编码器/解码器适配器类 都实现自 ChannelInboundHandler或ChannelOutboundHandler。
 
2】 SimpleChannelInboundHandler
继承自ChannelInboundHandlerAdapter;
用来处理进站消息;
需要实现抽象方法channelRead0(ChannelHandlerContext,T)来对消息进行处理;
    T为泛型,也就是解码后消息的类型;
 
例如:处理字符串
ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) {
        System.out.println(msg);
    }
});
         
3)ChannelHandlerContext
当 ChannelHandler 被添加到 ChannelPipeline 时,它将会被分配一个 ChannelHandlerContext;
其代表了 ChannelHandler 和 ChannelPipeline 之间的绑定;
 
ChannelHandlerContext的作用:
    可以获取Channel    ->channel()方法;
    可以获取管道    ->pipeline()方法;
    可以写出数据     ->write()/writeAndFlush()方法;  
 
4)关于write方法
    Channel、ChannelPipeline和ChannelHandlerContext都有write方法, 用来写出数据;
        Channel    -> Channel 上的 write()方法将会导致写入事件从尾端到头部地流经ChannelPipeline,并被每个ChannelOutboundHandler处理;
        ChannelPipeline    ->和Channel的write()方法一样,写出的出站消息都是从管道尾部开始向头部流动;
        ChannelHandlerContext    ->ChannelHandlerContext的write()方法,写出事件会从与ChannelHandlerContext绑定的前一个出站处理器开始向管道头部流动;
 
例如:有4个ChannelHandler
in1通过Channel写出,ctx.channel().write(xxx):
    则写出事件执行顺序为:out2    ->out1    ->管道头部
in1通过ChannelHandlerContext写出(ctx.write(xxx)):
    写出事件直接从in1的前一个处理器处理,这里in1前面没有出站处理器了,因此直接从管道头部出站;
 
in2通过Channel写出:out2    ->out1    ->管道头部;
in2通过ChannelHandlerContext写出:out1    ->管道头部;      
 
 
 
 
posted @ 2020-05-29 16:34  L丶银甲闪闪  阅读(142)  评论(0编辑  收藏  举报