Netty系列:三、Netty的关键组件

1.Netty中抽象的接口

主要有三种类型接口

  • Channel -> Socket
  • EventLoop -> 控制流、多线程处理、并发
  • ChannelFuture -> 异步通知

下面一一介绍

1.1.Channel接口

Channel的产生是为了降低网络传输变成的复杂性,它是传入传出数据的载体,可以打开或者关闭,连接或断开。可以当做它是Socket的升级。我们之前用的NioSocketChannel就是它的实现类。

内部结构:
netty

1.2.EventLoop接口

这个接口是Netty的核心抽象,用于处理连接中所发生的事件。

  • 一个EventLoopGroup包含一个或者多个EventLoop
  • 一个EventLoop在它的生命周期内只和一个Thread绑定
  • 所有的EventLoop处理IO事件都将传给它专有的Thread上处理
  • 一个Cahnnel在它的生命周期内只注册一个EventLoop
  • 一个EventLoop可能会被分配多个或者一个Channel
1.3.ChannelFuture接口

Netty中所有的IO操作都是异步的,一个操作不会立即返回,我们会在特定的事件点需要其返回结果。ChannelFuture接口就可以看做将来结果的占位符。

2.逻辑处理(Handler)和处理数据流(Pipe)接口

2.1.ChannelHandler接口

它充当了所有处理入站和出站数据的应用程序逻辑的容器。它的方法是由事件触发的。它可以用于几乎任何类型的动作,如数据格式转换或者异常抛出。
ChannelHandler有很多种类型,它的功能取决于它的超类,Netty以适配器的形式提供了大量的默认实现。默认适配器的存在是为了简化应用程序的开发过程。ChannelPipeline的每个ChannelHandler将负责将事件转发到下一个ChannelHandler。我们只需要重写那些需要特殊处理的方法和事件。

常用的适配器

  • 编码器、解码器
  • SimpleChannelInboundHandlerAdapter
2.1.1.编码器和解码器

所有的编码器/解码器适配器类型都实现了ChannelInboundHandlerChannelOutboundHandler接口。
当Netty接收或者发送一个消息时,就会有数据转换。入站数据会被解码,即从字节转换为另一种格式。如果出站则被编码为字节。

如果需要中间的一种格式,类似于Google的Protocol Buffers需要一种特别的格式,则可以自定义一种编码器、解码器。

2.1.2.抽象类SimpleChannelInboundHandlerAdapter
public class ClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    @Override
    //当被通知Channel是活跃的时候,发送一条消息
    public void channelActive(ChannelHandlerContext ctx) {
        ctx.writeAndFlush(Unpooled.copiedBuffer("Netty is No.1", CharsetUtil.UTF_8));
    }

    @Override
    //接收消息时会调用该方法
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("Client Recived:" + msg.toString(CharsetUtil.UTF_8));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

上面的代码中我们继承了SimpleChannelInboundHandlerAdapter抽象类,我们重写了channelRead0方法,并且得到了ChannelHandlerContext的引用,这个引用将作为参数传递给ChannelHandler的所有方法。

2.2.ChannelPipeline接口

ChannelPipeline提供了ChannelHandler链的容器,并定义了用于该链上传播入站和出站事件流的API。当Channel被创建时,它会被自动分配到他专属的ChannelPipeline

然我们看看ChannelHandler安装到ChannelPipeline中的过程

bootstrap.group(group)
    //适用于Nio传输的Channel类型
    .channel(NioSocketChannel.class)
    .remoteAddress(new InetSocketAddress(host, port))
    //ChannelInitializer的实例被注册到ServerBootstrap
    //在创建Channel时,向ChannelPipeline添加一个ClientHandler实例
    .handler(new ChannelInitializer<SocketChannel>() {
        protected void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new ClientHandler());
        }
    });

ChannelHandler有俩个子接口ChannelInboundHandlerChannelOutboundHandler分别处理入站和出站事件
举个例子:
netty
可以看出ChannelHandler接收事件、执行处理逻辑。并将数据传递给下一个ChannelHandler,他们的执行顺序是由他们被添加的顺序决定的。当然是ChannelPipeline给他们提供了平台。当然ChannelPipeline可以区分出是入站和出站,可以保证数据在相同类型的ChannelHandler之间传递。

3.引导

引导类主要作用是将一个进程连接到一个端口上,或者将一个进程连接到指定的主机上。一次有两种引导,一种是客户端Bootstrap和服务器ServerBootstrap
重要的一点
Bootstrap只需要一个EventLoopGroup,但是ServerBootstrap需要两个。因为一组在端口接听套接字,另一组用来处理传入的客户端连接。当然这两组可以是同一个引用。
netty

下一篇:http://blog.csdn.net/theludlows/article/details/79501294

猜你喜欢

转载自blog.csdn.net/TheLudlows/article/details/79463635