关于Netty的一些学习心得

本文介绍了高性能网络编程框架Netty的特点及应用。详细解释了Netty如何解决大规模并发连接的问题,并探讨了其核心组件如Channel、EventLoop等的功能与运作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近开始学习一个新的框架,为了防止自己学过之后就忘的坏习惯,所以写一些心得在这里。
1.首先Netty是个什么东西呢?

假设你正在为一个重要的大型公司开发一款全新的任务关键型的应用程序。在第一次会议
上,你得知该系统必须要能够扩展到支撑 150 000 名并发用户,并且不能有任何的性能损失,这
时所有的目光都投向了你。你会怎么说呢?
如果你可以自信地说:“当然,没问题。”那么大家都会向你脱帽致敬。但是,我们大多数人
可能会采取一个更加谨慎的立场,例如:“听上去是可行的。”然后,一回到计算机旁,我们便开
始搜索“high performance Java networking”(高性能 Java 网络编程)。

如果你现在搜索它,在第一页结果中,你将会看到下面的内容:

Netty: Home
netty.io/
Netty 是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器

和客户端。

最早期的java只是支持一些阻塞I/O,性能极差,每个线程只能处理一个客户端,如果访问客户稍多一点就会不停地创建线程,而我们都知道jvm的内存资源是极其宝贵得,如果一直创建线程就会导致jvm宕机或者内存溢出,所以早期一些大公司的处理方式都是通过c语言去处理这一块的逻辑。

后来出现了NIO,可以看做是NO I/O,也可以看做是NEW I/O。非阻塞式设计是可以一个线程对多个连接,线程池的创建可以把线程所占用的资源控制在自己手里,这样就可以避免内存溢出的异常。java中的选择器就是一个非阻塞式设计实现的关键,它可以使用较少的线程去处理较多的连接,没有I/O操作的时候也可以去处理其他业务。

尽管有一些公司直接去使用java NIO Api去构建一些工程,但是要正确和安全的使用这些Api却并不容易,所以最好还是把这些工作直接交给网络编程专家——Netty来实现。

2.Netty的一些特性

设计:

        统一的API,支持多种传输类型,阻塞式和非阻塞式。

        简单而强大的线程模型。

        链接逻辑支持复用。

易于使用:

        详细的javadoc和大量的例子

        不需要超过java1.6+支持(一些特性需要java1.7+支持)

性能:

        拥有比java核心API更高的吞吐量和更低的延迟

        因为池化,消耗更低的资源

        最少的内存复制

健壮性:

        不会因为快速、慢速或者超载而引发内存溢出异常

        消除在高速网络I/O中出现不公平读写的比率

社区:

        版本更新快速而且频繁

3.Netty核心组件

Channel、Future、回调、ChannelHandler、事件。

Channel代表了Netty的每一个基本构件,代表了Netty对每一个硬件的操作,打开关闭连接,读写操作。

Future提供了对应用程序的异步通知,可以把它看做是一个结果的占位符。它在未来的某个时刻完成。

回调是提供给另外方法对本方法的一个引用,后者可以适当的时候调用前者。

ChannelHandler是对进站的数据的逻辑处理,用来写我们的核心逻辑。

事件是Netty用来通知我们状态的改变或者是操作的状态得,通过事件的不同我们可以执行一些自己的操作,例如写一些日志啊,数据转换啊之类的事。

在这里我多说两个Netty的组件,它们是ChannelPipeline和EventLoop。ChannelPipeline可以看做是多个ChannelHandler的有序排列,数据是按照ChannelPipeline中ChannelHandler的顺序依次进行逻辑处理,进站和出站的ChannelHandler可以放在一个ChannelPipeline中,Netty会自动判断它是进站和出站的CahnnelHandler。EventLoop是Netty分给每个Channel的一个事件循环,用来注册事件,将事件分派给ChannelHandler,安排进一步的动作。

4.Channel、EventLoop、ChannelFuture、ChannelHandler、ChannelPipeline、编码器、解码器、引导程序
 Channel—Socket, Netty的Cahnnel接口提供的API大大降低了使用Socket类的复杂性。

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

     一个 EventLoopGroup 包含一个或者多个 EventLoop
     一个 EventLoop 在它的生命周期内只和一个 Thread 绑定;
     所有由 EventLoop 处理的 I/O 事件都将在它专有的 Thread 上被处理;
     一个 Channel 在它的生命周期内只注册于一个 EventLoop;
     一个 EventLoop 可能会被分配给一个或多个 Channel。
注意,在这种设计中,一个给定 Channel 的 I/O 操作都是由相同的 Thread 执行的,实际
上消除了对于同步的需要。

 ChannelFuture—异步通知。

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

 ChannelHandler——Netty主要组件

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

 ChannelPipeline——ChannelHandler 链的容器

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

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

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

       ChannelInitializer 将它自己从 ChannelPipeline 中移除。

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

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

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

为什么需要适配器类?
有一些适配器类可以将编写自定义的 ChannelHandler 所需要的努力降到最低限度,因为它们提
供了定义在对应接口中的所有方法的默认实现。
下面这些是编写自定义 ChannelHandler 时经常会用到的适配器类:
 ChannelHandlerAdapter
 ChannelInboundHandlerAdapter
 ChannelOutboundHandlerAdapter

 ChannelDuplexHandler

编码器和解码器

Netty发送一次消息就会发生一次数据转码,你将会发现对于入站数据来说,channelRead 方法/事件已经被重写了。对于每个从入站Channel 读取的消息,这个方法都将会被调用。随后,它将调用由预置解码器所提供的 decode()方法,并将已解码的字节转发给 ChannelPipeline 中的下一个 ChannelInboundHandler。

引导程序(Bootstrap和ServerBootstrap)

引导程序对于客户端和服务端是不同的,对于客户端来说是Bootstrap,对于服务端来说是ServerBootstrap。

这两种的区别是:

BootStrap和ServerBootStrap的比较
类别BootStrapServerBootStrap
网络编程中的作用链接到远程主机和端口绑定到一个本地端口
EventLoopGroup中的数量12

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


CAN长字节DM1报文是指在CAN总线上传输的长度超过8个字节的DM1报文。根据引用\[1\],当要传输的数据长度超过8个字节时,首先使用TPCM进行广播,广播内容包含即将传输报文的PGN、总的数据包长度等信息,然后使用TP.DT进行数据传输。相邻两个TP.DT之间的时间间隔是50ms到200ms。根据引用\[2\],当字节数大于8时,将会使用多帧传输参数组。根据引用\[3\],DM1报文是Diagnostic Message 1, Active Diagnostic Trouble Codes的缩写,用于点亮故障指示灯、红色停机灯等,并周期性播报控制器中处于激活状态的故障码。DM1报文的格式包括各个字节的定义,如故障指示灯、红色停机灯、琥珀色警告指示灯等。因此,CAN长字节DM1报文是指在CAN总线上传输的长度超过8个字节的DM1报文,用于传输更多的故障码信息。 #### 引用[.reference_title] - *1* [车载通信——J1939 DM1](https://blog.csdn.net/weixin_64064747/article/details/130193432)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [J1939广播DM1报文](https://blog.csdn.net/mengdeguodu_/article/details/108173263)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [J1939商用车在线诊断DM1报文](https://blog.csdn.net/traveller93/article/details/120735912)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值