Netty网络抽象的代表

Netty学习指北02

Posted by MistRay on September 9, 2019

Netty学习指北02

Netty网络抽象的代表

Channel,EventLoop,ChannelFuture结合在一起可以被认为是网络抽象的代表.

Channel->Socket

基本的I/O操作(bind,connect,read,write)依赖于底层网络传输所提供的原语. 在基于Java的网络编程中,其基本的构造是class Socket.NettyChannel接口锁提供的API, 大大的降低了直接使用Socket的复杂性.此外,Channel也是拥有许多预定义的,专门化实现的广泛类层次结构的根, 下面是一个简短的部分清单:

  • EmbeddedChannel
  • LocalServerChannel
  • NioDatagramChannel
  • NioSctpChannel
  • NioSocketChannel

EventLoop->控制流,多线程处理,并发

EventLoop定义了Netty的核心抽象,用于处理连接的生命周期中所发生的事件. post_2019_09_11_01.png

  • 一个EventLoopGroup包含一个或者多个EventLoop.
  • 一个EventLoop在它的生命周期内只和一个Thread绑定.
  • 所有由EventLoop处理的I/O事件都将在它专有的Thread上被处理
  • 一个Channel在它的生命周期内只注册于一个EventLoop
  • 一个EventLoop可能会被分配给一个或多个Channel

在这种设计中,一个给定Channel的I/O操作都是由相同的Thread执行的,实际上消除了对于同步的需要.

ChannelFuture->异步通知

Netty中所有的I/O操作都是异步的.因此一个操作可能不会立即返回,所以我们需要一种用于在之后某个时间点确定其结果的方法. 为此Netty提供了ChannelFuture接口,其addListener()方法注册了一个ChannelFutureListener, 以便在某个操作完成时(无论是否成功)得到通知.

可以将ChannelFuture看作是将来要执行的操作的结果的占位符. 它究竟什么时候被执行则可能取决于若干因素,因此不可能准确的预测,但是可以肯定的是它将会被执行.此外, 所有属于同一个Channel的操作都被保证其将以它们被调用的顺序被执行

ChannelHandler和ChannelPipeline简介

ChannelHandler

ChannelHandler它充当了所有处理入站和出站数据的应用程序逻辑的容器. 因为ChannelHandler的方法是由网络事件触发的. ChannelHandler可专门用于几乎任何类型的动作, 例如将数据从一种格式转换为另一种格式,或者处理转换过程中所抛出的异常.

ChannelHandler的子类型(编码器,解码器,SimpleChannelInboundHandler,
ChannelOutboundHandler等)将在后面的post中进行分析.

ChannelPipeline

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

ChannelHandler安装到ChannelPipeline中的过程:

  • 一个ChannelInitializer的实现被注册到了ServerBootstrap中.
  • ChannelInitializer.initChannel()方法被调用时,ChannelInitializer将在ChannelPipeline上安装一组自定义ChannelHandler.
  • ChannelInitializer将它自己从ChannelPipeline上移除.

当然我们也可以在ChannelHandler执行中对ChannelPipeline进行操作 (例如根据业务逻辑对Channel绑定的ChannelPipeline进行增加,删除ChannelHandler等操作).


@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    Channel channel = ctx.channel();
    // 对指定的Channel绑定的ChannelPipeline进行操作->添加心跳定时器
    channel.pipeline().addFirst("idleStateHandler", new IdleStateHandler(maxWaitTimeout, 0, 0, TimeUnit.SECONDS));
}

Reference