【Netty】大白话 Netty 核心组件分析
Bytebuf(字节容器)
网络通信最终都是通过字节流进行传输的。 ByteBuf
就是 Netty 提供的一个字节容器,其内部是一个字节数组。 当我们通过 Netty 传输数据的时候,就是通过 ByteBuf
进行的。
我们可以将 ByteBuf
看作是 Netty 对 Java NIO 提供了 ByteBuffer
字节容器的封装和抽象。
有很多小伙伴可能就要问了 : 为什么不直接使用 Java NIO 提供的 ByteBuffer
呢?
因为 ByteBuffer
这个类使用起来过于复杂和繁琐。
Bootstrap 和 ServerBootstrap(启动引导类)
Bootstrap
是客户端的启动引导类/辅助类,具体使用方法如下:
EventLoopGroup group = new NioEventLoopGroup();try {//创建客户端启动引导/辅助类:BootstrapBootstrap b = new Bootstrap();//指定线程模型b.group(group).......// 尝试建立连接ChannelFuture f = b.connect(host, port).sync();f.channel().closeFuture().sync();} finally {// 优雅关闭相关线程组资源group.shutdownGracefully();}
ServerBootstrap
客户端的启动引导类/辅助类,具体使用方法如下:
// 1.bossGroup 用于接收连接,workerGroup 用于具体的处理EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();try {//2.创建服务端启动引导/辅助类:ServerBootstrapServerBootstrap b = new ServerBootstrap();//3.给引导类配置两大线程组,确定了线程模型b.group(bossGroup, workerGroup).......// 6.绑定端口ChannelFuture f = b.bind(port).sync();// 等待连接关闭f.channel().closeFuture().sync();} finally {//7.优雅关闭相关线程组资源bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
从上面的示例中,我们可以看出:
Bootstrap
通常使用connet()
方法连接到远程的主机和端口,作为一个 Netty TCP 协议通信中的客户端。另外,Bootstrap
也可以通过bind()
方法绑定本地的一个端口,作为 UDP 协议通信中的一端。ServerBootstrap
通常使用bind()
方法绑定本地的端口上,然后等待客户端的连接。Bootstrap
只需要配置一个线程组—EventLoopGroup
,而ServerBootstrap
需要配置两个线程组—EventLoopGroup
,一个用于接收连接,一个用于具体的 IO 处理。
Channel(网络操作抽象类)
Channel
接口是 Netty 对网络操作抽象类。通过 Channel
我们可以进行 I/O 操作。
一旦客户端成功连接服务端,就会新建一个 Channel
同该用户端进行绑定,示例代码如下:
// 通过 Bootstrap 的 connect 方法连接到服务端public Channel doConnect(InetSocketAddress inetSocketAddress) {CompletableFuture<Channel> completableFuture = new CompletableFuture<>();bootstrap.connect(inetSocketAddress).addListener((ChannelFutureListener) future -> {if (future.isSuccess()) {completableFuture.complete(future.channel());} else {throw new IllegalStateException();}});return completableFuture.get();}
比较常用的Channel
接口实现类是 :
NioServerSocketChannel
(服务端)NioSocketChannel
(客户端)
这两个 Channel
可以和 BIO 编程模型中的ServerSocket
以及Socket
两个概念对应上。
EventLoop(事件循环)
EventLoop 介绍
这么说吧!EventLoop
(事件循环)接口可以说是 Netty 中最核心的概念了!
《Netty 实战》这本书是这样介绍它的:
EventLoop
定义了 Netty 的核心抽象,用于处理连接的生命周期中所发生的事件。
是不是很难理解?说实话,我学习 Netty 的时候看到这句话是没太能理解的。
说白了,EventLoop
的主要作用实际就是责监听网络事件并调用事件处理器进行相关 I/O 操作(读写)的处理。
Channel 和 EventLoop 的关系
那 Channel
和 EventLoop
直接有啥联系呢?
Channel
为 Netty 网络操作(读写等操作)抽象类,EventLoop
负责处理注册到其上的Channel
的 I/O 操作,两者配合进行 I/O 操作。
EventloopGroup 和 EventLoop 的关系
EventLoopGroup
包含多个 EventLoop
(每一个 EventLoop
通常内部包含一个线程),它管理着所有的 EventLoop
的生命周期。
并且,EventLoop
处理的 I/O 事件都将在它专有的 Thread
上被处理,即 Thread
和 EventLoop
属于 1 : 1 的关系,从而保证线程安全。
下图是 Netty NIO 模型对应的 EventLoop
模型。通过这个图应该可以将EventloopGroup
、EventLoop
、 Channel
三者联系起来。
https://www.jianshu.com/p/128ddc36e713
ChannelHandler(消息处理器) 和 ChannelPipeline(ChannelHandler 对象链表)
下面这段代码使用过 Netty 的小伙伴应该不会陌生,我们指定了序列化编解码器以及自定义的 ChannelHandler
处理消息。
b.group(eventLoopGroup).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {ch.pipeline().addLast(new NettyKryoDecoder(kryoSerializer, RpcResponse.class));ch.pipeline().addLast(new NettyKryoEncoder(kryoSerializer, RpcRequest.class));ch.pipeline().addLast(new KryoClientHandler());}});
ChannelHandler
是消息的具体处理器,主要负责处理客户端/服务端接收和发送的数据。
当 Channel
被创建时,它会被自动地分配到它专属的 ChannelPipeline
。 一个Channel
包含一个 ChannelPipeline
。 ChannelPipeline
为 ChannelHandler
的链,一个 pipeline 上可以有多个 ChannelHandler
。
我们可以在 ChannelPipeline
上通过 addLast()
方法添加一个或者多个ChannelHandler
(一个数据或者事件可能会被多个 Handler 处理) 。当一个 ChannelHandler
处理完之后就将数据交给下一个 ChannelHandler
。
当 ChannelHandler
被添加到的 ChannelPipeline
它得到一个 ChannelHandlerContext
,它代表一个 ChannelHandler
和 ChannelPipeline
之间的“绑定”。 ChannelPipeline
通过 ChannelHandlerContext
来间接管理 ChannelHandler
。
https://www.javadoop.com/post/netty-part-4
ChannelFuture(操作执行结果)
public interface ChannelFuture extends Future<Void> {Channel channel();ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> var1);......ChannelFuture sync() throws InterruptedException;
}
Netty 是异步非阻塞的,所有的 I/O 操作都为异步的。
因此,我们不能立刻得到操作是否执行成功,但是,你可以通过 ChannelFuture
接口的 addListener()
方法注册一个 ChannelFutureListener
,当操作执行成功或者失败时,监听就会自动触发返回结果。
ChannelFuture f = b.connect(host, port).addListener(future -> {if (future.isSuccess()) {System.out.println("连接成功!");} else {System.err.println("连接失败!");}
}).sync();
并且,你还可以通过ChannelFuture
的 channel()
方法获取连接相关联的Channel
。
Channel channel = f.channel();
另外,我们还可以通过 ChannelFuture
接口的 sync()
方法让异步的操作编程同步的。
//bind()是异步的,但是,你可以通过 `sync()`方法将其变为同步。
ChannelFuture f = b.bind(port).sync();
【Netty】大白话 Netty 核心组件分析相关推荐
- 【Netty】Netty 核心组件 ( ChannelPipeline 中的 ChannelHandlerContext 双向链表分析 )
文章目录 一. 代码示例分析 二. ChannelHandlerContext 双向链表类型 三. Pipeline / ChannelPipeline 管道内双向链表分析 四. 数据入站与出站 接上 ...
- 【Netty】Netty 核心组件 ( ChannelHandlerContext )
文章目录 一. ChannelHandlerContext 组件 二. ChannelHandlerContext 组件 debug 调试 三. ChannelHandlerContext 组件 de ...
- 【Netty】IO 模型简介 ( Netty 特点 | Netty 应用场景 | Java 三种 IO 模型 | BIO 模型 )
文章目录 I . Netty 简介 II . Netty 应用场景 III . Java I/O 模型 IV . BIO 概念 V . BIO 开发流程 VI . BIO 实例 VII . BIO 模 ...
- 【Netty】Netty 简介 ( 原生 NIO 弊端 | Netty 框架 | Netty 版本 | 线程模型 | 线程 阻塞 IO 模型 | Reactor 模式引入 )
文章目录 一. NIO 原生 API 弊端 二. Netty 简介 三. Netty 架构 四. Netty 版本 五. Netty 线程模型 六. 阻塞 IO 线程模型 七. 反应器 ( React ...
- Netty自学-Netty学习(一)
什么Netty? Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序. 关注公众号,我们一 ...
- 【初识Netty使用Netty实现简单的客户端与服务端的通信操作Netty框架中一些重要的类以及方法的解析】
一.Netty是什么? Netty 由 Trustin Lee(韩国,Line 公司)2004 年开发 本质:网络应用程序框架 实现:异步.事件驱动 特性:高性能.可维护.快速开发 用途:开发服务器和 ...
- SpringBoot2+Netty+WebSocket(netty实现websocket)
##### 一.SpringBoot2+Netty+WebSocket(netty实现websocket,支持URL参数) 原文链接: https://zhengkai.blog.csdn.net/a ...
- Netty Channel源码分析
原文:https://wangwei.one/posts/netty-channel-source-analyse.html 前面,我们大致了解了Netty中的几个核心组件.今天我们就来先来介绍Net ...
- Netty Pipeline源码分析(2)
原文链接:https://wangwei.one/posts/net... 前面 ,我们分析了Netty Pipeline的初始化及节点添加与删除逻辑.接下来,我们将来分析Pipeline的事件传播机 ...
最新文章
- oracle收集统计计划,oracle收集统计信息之analyze
- Struts 2的基石——拦截器(Interceptor)
- @property和@setter和@getter
- php input 数组的值,如何获取2值表单输入数组到PHP数组中(How to get 2 value form input array into PHP array)...
- SSIS 学习(2):数据流任务(上)
- 卡通驱动项目ThreeDPoseTracker——模型驱动解析
- JavaScript语义基础
- 微软开源P语言,实现安全的异步事件驱动编程
- IntelliJ IDEA for Mac 彻底卸载/彻底删除
- 【C++ grammar】引用
- J2EE WEBWORK FRAMEWORK安全隐患
- mysql 开启事务_MySQL可重读隔离级别的底层实现原理
- CABasicAnimation 使用
- protected的继承方式有什么特点_草莓的授粉方式有哪些?各有什么特点
- Linux内核4.17再获捷报
- c语言邻接表存储拓扑排序,拓扑排序(完整案列及C语言完整代码实现)
- 三层交换机配置的步骤
- 千兆路由器怎么设置网速最快_千兆路由器怎么设置才能发挥最好【图】
- 怎么将英文的PDF翻译成中文的
- D3.js学习笔记七:多系列折线图与图例
热门文章
- 人类是怎么从猩猩身上惹来艾滋病的?人与兽的关系很单纯!
- 0与1c语言编译,C语言程序设计(07776-1)第11章编译预处理课案.ppt
- R语言ggplot2可视化分面图、在分面图中的每个直方图中添加均值文本标签、添加均值红色竖线
- R语言ggplot2可视化条形图可视化控制底部和x轴之间没有空格实战:即条形图的底部直接和坐标轴连接
- R语言将dataframe长表转化为宽表实战:使用reshape函数、使用tidyr包的spread函数、使用data.table
- Error in do_one(nmeth) : NA/NaN/Inf in foreign function call (arg 1)
- python使用fpdf生成数据报告pdf文件
- 长连接、短连接、短轮询、长轮询
- python使用imbalanced-learn的RepeatedEditedNearestNeighbours方法进行下采样处理数据不平衡问题
- python进行探索性数据分析EDA(Exploratory Data Analysis)分析