资讯专栏INFORMATION COLUMN

Netty组件入门学习

qpal / 2331人阅读

摘要:可以用来接收入站事件和数据,随后使用应用程序的业务逻辑进行处理。因为用户并不是关心所有的事件,因此提供了抽象类和。抽象类最常见的一个情况,你的应用程序会利用一个来接受解码消息,并对该数据应用业务逻辑。

Channel、EventLoop和ChannelFuture

Channel——Socket;

EventLoop——控制流、多线程处理、并发

ChannelFuture异步通知

Channel接口

基于I/O操作(例如:bind()、connect()、read()和write())依赖于底层网络传输提供的原语。在基于Java的网络编程中,其基本构造为类Socket。

Netty的Channel接口所提供的API,大大降低了直接使用Socket类的复杂性。

Channel拥有许多预定义的、专门化实现的广泛类层次结构的根,如下:

EmbeddedChannel

LocalServerChannel

NioDatagramChannel

NioSctpChannel

NioSocketChannel

EventLoop接口

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

Channel、EventLoop、Thread、EventLoopGroup关系示意图

一个EventLoopGroup包含一个或者多个EventLoop

一个EventLoop在它的生命周期内只和一个Thread绑定

所有由EventLoop处理的I/O事件都将在它专有的Thread上被处理

一个Channel在它的生命周期内只注册于一个EventLoop

一个EventLoop可能会被分配一个或多个Channel

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

ChanneFuture接口

Netty中所有的I/O操作都是异步的,因为一个操作不可能立即返回,所以我们需要一种用于在之后的某个时间点确定其结果的方法。

因此Netty提供了ChannelFuture接口,其addListener()方法注册了一个ChannelFutureListener,以便在某个操作完成时(无论是否成功)得到通知。

ChannelHandler和ChannelPipeline

主要用来管理数据流已经执行应用程序处理逻辑

ChannelHandler接口

ChannelHandler充当了所有处理入站和出站数据的应用程序逻辑的容器。

ChannelHandler可专门用于几乎任何类型的动作,例如将数据从一种格式转换为另外一种格式,或者处理转换过程中所抛出的异常。

ChannelHandler可以用来接收入站事件和数据,随后使用应用程序的业务逻辑进行处理。当你的客户端需要发送响应时,可以从ChannelInboundhandler冲刷数据。

你的应用程序的业务逻辑通常驻留在一个或者多个ChannelInboundHandler中。

ChannelPipeline

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

ChannelHandler被安装到ChannelPipeline中过程如下:

一个ChannelInitializer的实现被注册到了ServerBootstrap中

当ChannelInitializer.initChannel()方法被调用时,ChannelInitalizer将在ChannelPipeline中安装一组自定义的ChannelHandler

ChannelInitializer将它自己从ChannelPipeline中移除

 ChannelHandler可以让事件流经ChannelPipeline,它们是在应用程序的初始化或者引导阶段被安装的。这些对象接收事件、执行它们所实现的处理逻辑,并将数据传递给链中的下一个ChannelHandler。它们的执行顺序是由它们被添加的顺序决定的

ChannelPipeline是这些ChannelHandler的编排顺序。

入站和出站ChannelHandler可以被安装到同一个ChannelPipeline中。如果一个消息或者任何其他的入站事件被读取,那么它会从ChannelPipeline的头部开始流动,并被传递给第一个ChannelInboundHandler。这个ChannelHandler不一定会实际地修改数据,具体取决于它的具体功能,在这之后,数据将会被传递给链中的下一个ChannelInboundHandler。最终,数据会到达ChannelPipeline的尾端,届时,所有处理就都结束了。

出站数据将会从ChannelOutboundHandler链的尾端开始流动,直到它到达链的头部为止。在这之后,出站数据将会到达网络传输层。

通过使用作为参数传递到每个方法的ChannelHandlerContext,事件可以被传递给当前ChannelPipeLine中的下一个ChannelHandler。因为用户并不是关心所有的事件,因此Netty提供了抽象类ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter。通过调用ChannelHandlerContext上的对应的方法,都可以简单地将事件传递给下一个ChannelHandler的方法的实现。

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

在Netty中,有两种发送消息的方式:

直接写到Channel中,会导致消息从ChannelPipeline的尾端开始流动

写到和ChannelHandler相关联的ChannelHandlerContext对象中,会导致消息从ChannelPipeline中的下一个ChannelHandler开始流动

如果将两个类别(Inboud和Outbound)的ChannelHandler都混合添加到一个ChannelPipeline会发生什么?

虽然ChannelInboundHandler和ChannelOutboundHandler都扩展自ChannelHandler,但是Netty可以区分两种Handler的实现,并确保数据只会在具有相同定向类型的两个ChannelHandler之间传递。

深入了解ChannelHandler

不同类型的ChannelHandler各自的功能主要取决于它们的超类。Netty以适配器类的形式提供了大量默认的ChannelHandler实现,其旨在简化应用程序处理逻辑的开发过程。

这些适配器类可以自动将事件转发到ChannelPipeline中的下一个ChannelHandler,所以你可以只重写那些你想要特殊处理的方法和事件。

为什么需要适配器?

有一些适配器类可以将编写自定义的ChannelHanlder所需要的努力降到最低限度,因为它们提供了定义在对应接口中的所有方法的默认实现。
常用的适配器类有:

ChannelHandlerAdapter

ChannelInboundHandlerAdapter

ChannelOutboundHandlerAdapter

ChannelDuplexHandler

编码解码器

所有由Netty提供的编码/解码适配器类都实现了ChannelOutboundHandler或者ChannelInboundHandler接口。

对于入站数据,channelRead方法已经被重写了。对于每一个从入站Channel读取的消息,这个方法都会被调用。随后,它将调用由预置解码器提供的decode()方法,并将已解码的字节转发给ChannelPipeline中的下一个ChannelHandler,出站相反。

抽象类SimpleChannelInboundHandler

最常见的一个情况,你的应用程序会利用一个ChannelHandler来接受解码消息,并对该数据应用业务逻辑。要创建一个这样的ChannelHandler,只需要扩展SimpleChannelInboundHandler,其中是你要处理的消息的Java类型。

在这个ChannelHandler中,你将需要重写基类的一个或者多个方法,并且获取一个ChannelHandlerContext的引用,这个引用将作为参数传递给ChannelHandler的所有方法。

在这种类型的ChannelHandler中,最重要的方法是channelRead0(ChannelHandlerContext , T)。除了要求不阻塞当前的I/O线程之外,其具体实现完全取决于你。

引导

Netty的引导类为应用程序的网络层配置提供了容器。

用于客户端(Bootstrap)引导,将一个进程连接到另一个运行在某个指定主机的指定端口上的进程。

用于服务器(ServerBootstrap)引导,将一个进程绑定到某个指定的端口

Bootstrap类比较

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

区别分析:

ServerBootstrap将绑定到一个端口,因为服务器必须要监听连接,而Bootstrap则是由想要连接到远程节点的客户端应用程序所使用的。

为什么服务端需要两个EventLoopGroup(可以是同一个实例)?因为服务器需要两组不同的Channel。第一组将只包含一个ServerChannel,代表服务器自身的已绑定到某个本地端口第二次正在监听的套接字。第二组包含所有已经创建的用来处理传入客户端连接(对于每个服务器已经接受的连接都一个)的Channel。

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

具有两个EventLoopGroup的服务器

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69275.html

相关文章

  • 慕课网_《Netty入门之WebSocket初体验》学习总结

    时间:2018年04月11日星期三 说明:本文部分内容均来自慕课网。@慕课网:https://www.imooc.com 教学源码:https://github.com/zccodere/s... 学习源码:https://github.com/zccodere/s... 第一章:课程介绍 1-1 课程介绍 什么是Netty 高性能、事件驱动、异步非阻塞的IO Java开源框架 基于NIO的客户...

    Noodles 评论0 收藏0
  • Spring Boot 2 快速教程:WebFlux 快速入门(二)

    摘要:响应式编程是基于异步和事件驱动的非阻塞程序,只是垂直通过在内启动少量线程扩展,而不是水平通过集群扩展。三特性常用的生产的特性如下响应式编程模型适用性内嵌容器组件还有对日志消息测试及扩展等支持。 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 02:WebFlux 快速入门实践 文章工程: JDK...

    gaara 评论0 收藏0
  • Netty入门学习-ByteBuf

    摘要:使用来优化套接字操作,尽可能消除由的缓冲区实现所导致的性能以及内存使用率的惩罚,这种优化发生在的核心代码中,不会被暴露出来。当前将会被增加所写入的字节数。 ByteBuf是Java NIO ByteBuffer的替代品,是网络数据基本单位字节的容器。 ByteBuf的API Netty的数据处理API通过两个组件暴漏:抽象类ByteBuf和接口ByteBufHolder ByteBuf...

    beanlam 评论0 收藏0
  • Java学习必备书籍推荐终极版!

    摘要:实战高并发程序设计推荐豆瓣评分书的质量没的说,推荐大家好好看一下。推荐,豆瓣评分,人评价本书介绍了在编程中条极具实用价值的经验规则,这些经验规则涵盖了大多数开发人员每天所面临的问题的解决方案。 很早就想把JavaGuide的书单更新一下了,昨晚加今天早上花了几个时间对之前的书单进行了分类和补充完善。虽是终极版,但一定还有很多不错的 Java 书籍我没有添加进去,会继续完善下去。希望这篇...

    Steve_Wang_ 评论0 收藏0
  • 从Java Socket非阻塞到Netty入门流程

    摘要:事件循环新连接接入连接上的数据读取抽象连接抽象业务逻辑处理读写数据期间的业务层动态链处理多个组成,让消息可以层层处理数据接收基本的数据处理基于公众号猫说学习交流群现架构设计码农兼创业技术顾问,不羁平庸,热爱开源,杂谈程序人生与不定期干货。 本博客 猫叔的博客,转载请申明出处阅读本文约 4分钟 适读人群:同学 Java IO,Socket非阻塞通信流程 这里我们使用一个内嵌的永久循环,...

    fsmStudy 评论0 收藏0

发表评论

0条评论

qpal

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<