Netty的组件和设计

Posted by kyle on June 28, 2018

Channel、EventLoop和ChannelFuture

可以认为有这样的抽象关系:

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

Channel接口

基本的I/O操作依赖于底层网络传输所提供的原语。在基于Java的网络编程中,其基本的构造是class Socket。Netty的Channel接口所提供的API,大大地降低了直接使用Socket类的复杂性。此外,Channel也拥有许多预定义的、专门化实现的广泛类层次结构的根。

EventLoop接口

EventLoop定义了Netty的核心抽象,用于处理连接的生命周期中所发生的事件。下图说明了Channel、EventLoop、Thread以及EventLoopGroup之间的关系:

简要说来:

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

ChannelFuture接口

Netty中所有的I/O操作都是异步的,ChannelFuture接口的addListener()方法注册了一个ChannelFutureListener,以便在某个操作完成时(无论是否成功)得到通知。

ChannelHandler和ChannelPipeline

ChannelHandler接口

从应用程序开发人员的角度来看,Netty的主要组件是ChannelHandler,它充当了所有处理入站和出站数据的应用程序逻辑的容器。

ChannelPipeline接口

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

ChannelHandler安装到ChannelPipeline中的过程如下所示:

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

当ChannelHandler被添加到ChannelPipeline时,它将会被分配一个ChannelHandlerContext,其代表了ChannelHandler和ChannelPipeline之间的绑定。虽然这个对象可以被用于获取底层的Channel,但是它主要还是被用于写出站数据。

在Netty中,有两种发送消息的方式。你可以直接写到Channel中,也可以写到和ChannelHandler相关联的ChannelHandlerContext对象中。前一种方式将会导致消息从ChannelPipeline的尾端开始流动,而后者将导致消息从ChannelPipeline中的下一个ChannelHandler开始流动。

编码器和解码器

当通过Netty发送或者接收一个消息的时候,就将会发生一次数据转换。入站消息会被解码,也就是说,从字节转换为另外一种格式,通常是一个Java对象。如果是出站消息,则会发生相反方向的转换:它将从它的当前格式被编码为字节。

抽象类SimpleChannelInboundHandler

应用程序里利用ChannelHandler来接收解码消息,并对该数据应用业务逻辑。要创建这样一个ChannelHandler,只需要扩展基类SimpleChannelInboundHandler,其中T是要处理的消息的Java类型。在这个ChannelHandler中,需要重写基类的一个或者多个方法,并且获取一个到ChannelHandlerContext的引用,这个引用将作为输入参数传递给ChannelHandler的所有方法。

在这种类型的ChannelHandler中,最重要的方法是ChannelRead0(ChannelHandlerContext, T)。

引导

有两种类型的引导。一种用于客户端,简单地称为:Bootstrap;而另一种用于服务器,名称是:ServerBootstrap。

两者的区别:

类别 Bootstrap ServerBootstrap
网络编程中的作用 连接到远程主机和端口 绑定到一个本地端口
EventLoopGroup 1 2

引导一个客户端只需要一个EventLoopGroup,为什么ServerBootstrap需要两个呢?

因为服务器需要两组不同的Channel。第一组将只包含一个ServerChannel,代表服务器自身的已绑定到某个本地端口的正在监听的套接字。而第二组将包含所有已创建的用来处理传入客户端连接的Channel。

与ServerChannel相关联的EventLoopGroup将分配一个负责为传入连接请求创建Channel的EventLoop。一旦连接被接受,第二个EventLoopGroup就会给它的Channel分配一个EventLoop。