Netty的组件和设计

目录

1.Channel、EventLoop和ChannelFuture

1.1 Channel接口

1.2 EventLoop接口

1.3 ChannelFuture接口

2.ChannelHandler和ChannelPipeline

2.1 ChannelHandler接口

2.2 ChannelPipeline接口

2.3 编码器和解码器

2.4 抽象类SimpleChannelInboundHandler

3.引导

4.小结


本章我们要详细地研究Netty的各个组件,看看它们是如何通过协作来支撑这些体系结构上的最佳实践的。

1.Channel、EventLoop和ChannelFuture

Channel、EventLoop和ChannelFuture类合在一起,可以被认为是Netty网络抽象的代表:

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

1.1 Channel接口

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

  • EmbeddedChannel
  • LocalServerChannel
  • NioDatagramChannel
  • NioSctpChannel
  • NioSocketChannel

1.2 EventLoop接口

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

这些关系是:

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

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

1.3 ChannelFuture接口

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

2.ChannelHandler和ChannelPipeline

2.1 ChannelHandler接口

ChannelHandler的方法是由网络事件触发的,它在Netty中充当了处理入站和出站数据的应用程序逻辑的容器。Netty中有许多不同类型的ChannelHandler,它们各自的功能主要取决于它们的超类。Netty以适配器类的形式提供了大量默认的ChannelHandler实现,目的是为了简化应用程序处理逻辑的开发过程。

我们知道,ChannelPipeline中的每个ChannelHandler将负责把事件转发到链中的下一个ChannelHandler。这些适配器类将自动执行这个操作,所以我们只需要重写那些需要特殊处理的方法和事件。

2.2 ChannelPipeline接口

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

  1. 一个ChannelInitializer的实现被注册到了ServerBootstrap(或客户端的BootStrap)
  2. 当ChannelInitializer.initChannel()方法调用时,ChannelIntializer将在ChannelPipeline中安装一组自定义的ChannelHandler
  3. ChannelIntializer将它自己从ChannelPipeline中移除。

ChannelHandler接收事件、执行它们所实现的处理逻辑,并将数据传递给链中的下一个ChannelHandler。它们的执行顺序是由它们被添加的顺序所决定的。实际上,被我们成为ChannelPipeline的是这些ChannelHandler的编排顺序。示意图如下:

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

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

2.3 编码器和解码器

由于网络数据总是一系列的字节,当你通过Netty发送或者接收一个消息的时候,将会发生一次转换。入站消息会被解码,一般情况下是从字节转换为一个Java对象。如果是出站消息,则会发生相反方向的转换,从它的当前格式转换为字节。

2.4 抽象类SimpleChannelInboundHandler

我们使用Netty最常见的情况是,创建一个ChannelHandler来接收解码消息,并对数据进行处理。要创建一个这样的ChannelHandler,我们只需要扩展基类SimpleChannelInboundHandler<T>,其中T是我们要处理的Java类型。在这个ChannelHandler中,我们需要重写基类的一个或者多个方法,并且获取一个到ChannelHandlerContext的引用,这个引用将作为输入参数传递给ChannelHandler的所有方法。

3.引导

Netty的引导类为应用程序的网络层配置提供了容器,这涉及将一个进程绑定到某个指定的端口,或者将一个进程连接到另一个运行在某个指定主机的指定端口上的进程。这两种类型的引导,一种用于客户端(BootStrap),一种用于服务端(ServerBootstrap)。

BootStrap和ServerBootStrap有一个明显的区别:引导一个客户端只需要一个EventLoopGroup,但是一个ServerBootstrap则需要两个(也可以是同一个实例)。因为服务器需要两组不同的Channel,一组只包含一个ServerChannel,代表服务器自身的已绑定到某个本地端口的正在监听的套接字。一组将包含所有已创建的用来处理传入客户端连接(对于每个服务器已经接受到连接都有一个)的Channel。

具有两个EventLoopGroup的服务器

 

4.小结

本章主要重新审视了之前引入的一些概念和组件,特别是ChannelHandler、ChannelPipeline和引导。

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值