Netty 笔记
1、Netty 是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器和客户端。
2、早期Java API 使用的阻塞函数
// 创建一个新的ServerSocket,用以监听指定端口上的连接请求
ServerSocket serverSocket = new ServerSocket(portNumber);
// 对 accept的调用将被阻塞,直到一个连接建立
SufferedReader in = serverSocket.accept();
— 这种方案,任何时候都有大量线程在休眠,资源浪费。每个线程的调用栈分配内存,默认64KB – 1MB。多线程上下文切换开销巨大。
3、Java NIO 非阻塞调用
一个单一的线程就可以处理多个并发连接。
4、Netty 的特性总结
【1】设计 统计API,支持多种传输类型(阻塞的和非阻塞的),简单强大的线程模型,真正无连接数据报套接字支持,连接逻辑组件支持复用。
【2】易于使用
【3】性能 比Java核心API更高的吞吐量和更低的延迟
【4】健壮性 不会因为慢速、快速、超载的连接导致OutOfMemoryError,消除高速网络中NIO常见的不公平读\写比率
【5】安全性 完整的SSL\TLS\StartTLS支持
【6】社区驱动 发布快速且频繁
5、Netty 核心组件
Channel 传入、传出数据的载体
回调 一个方法,一个指向已经被提供给另一个方法的方法的引用
Future 提供了另一种在操作完成时通知应用程序的方式。(将来提供对其结果的访问)
事件和ChannelHandler 事件是对我们的通知(改变状态、记录日志等)。 ChannelHandler 一种为了响应特定事件而执行的回调。
6、Echo服务器
所有Netty服务器都需要的两部分:
【1】至少一个ChannelHeadler 该组件实现了服务器对从客户端接收的数据的处理(业务逻辑)
【2】引导 配置服务器启动代码。 将服务器绑定到它要监听连接请求的端口上。
7、Echo服务器端 方法
channelRead() 对于每个传入的消息都要调用
channelReadComplete() 通知ChannelInboundHandler最后一次对channelRead()的调用是当前批量读取中的最后一条消息。
exceptionCaught() 读取期间,有异常抛出会调用。
(在方法内打印异常并关闭。如果不捕获异常,接收的异常会
被传递到ChannelPipeline尾端并记录。 应用程序应该提供至少一个实现exceptionCaught()
方法的channelHandler。 )
8、ChannelHandler
针对不同类型事件调用ChannelHandler
应用程序通过实现或者扩展ChannelHandler来挂钩到事件的生命周期,并且提供自定义的应用程序逻辑。
架构上,ChannelHandler用于保持业务逻辑与网络处理代码的分离。简化开发过程。
9、传输
因特网通信是建立在TCP传输之上的,NIO传输大多时候指的就是TCP传输(除了一些由Java NIO实现提供的服务器端性能)。
10、Echo客户端
(1)连接到服务器
(2)发送一个或多个消息
(3)对每个消息,等待并接收从服务器发回的相同的消息。
(4)关闭连接
主要代码:【业务逻辑】【引导】
11、Echo客户端 方法
channelActive() 与服务器建立连接后 调用
channelRead0() 接收到服务器消息后 调用
exceptionCaught() 处理过程中有异常时 调用
12、客户端 继承 SimpleChannelInboundHandler 与 服务端 继承ChannelInboundHandlerAdapter 原因
在客户端:当ChannelRead0完成时,已经传入消息并处理完。该方法返回后,SimpleChannelInboundHandler会释放指定的内存应用。
在客户端:仍然需要将消息返回给发送者,write()是异步操作,ChannelInboundHandlerAdapter 不会释放消息内存。内存在channelReadComplete()方法中,writeAndFlush()方法被调用时被释放。
13、Netty网络抽象代表,三大接口
Channel – Socket
EventLoop – 控制流、多线程处理、并发(Netty核心抽象,处理连接的生命周期中发生的事件)
ChannelFuture – 异步通知
14、ChannelHandler 和 ChannelPipeline
ChannelHandler 充当了所有处理入站和出站数据的应用程序逻辑的容器
ChannelPipeline 为ChannelHandler链提供了容器
(可以在ChannelPipeline 中将ChannelHandler 链接在一起以组织处理逻辑)
15、入站和出站
入站:事件运动方向是从 服务端 到 客户端
出站:事件运动方向是从 客户端 到 服务端 (例:客户端是内,服务端是外 外->内 :入; 内->外:出)
16、编码器和解码器
入站消息会被解码
出站消息会被编码
17、引导
Netty引导类为应用程序的网路层提供容器。
将一个进程绑定到某个指定的端口。
或者 将一个进程连接到另一个运行在某个指定主机的指定端口上的进程。
两种引导,一种用于客户端(Bootstrap),一种用于服务端(ServerBootStrap)
类别 |
Bootstrap |
ServerBootStrap |
网络编程中的作用 |
连接到远程主机和端口 |
绑定到一个本地端口 |
EventLoopGroup |
1 |
2 |
18、ChannelHandler 典型用途
(1)将数据从一种格式转换为另一种格式
(2)提供异常的通知
(3)提供Channel变为活动的或者非活动的通知
(4)提供当Channel注册到EventLoop或者从EventLoop注销时的通知
(5)提供有关用户自定义事件的通知
19、Channel 方法
方法名 |
描述 |
eventLoop |
返回分配给Channel 的EventLoop |
pipeline |
返回分配给Channel 的 ChannelPipeline |
isActive |
如果Channel是活动的,返回true,活动的意义可能依赖于底层的传输。 (例:一个Socket 传输一旦连接到远程节点便是活动的,一个Datagram传输一旦被打开便是活动的) |
localAddress |
返回本地的SocketAddress |
remoteAddress |
返回远程的SocketAddress |
write |
将数据写到远程节点。数据将被传递给ChannelPipeline,并排队知道数据被冲刷 |
flush |
将之前已写的数据冲刷到底层传输,(如一个socket) |
writeAndFlush |
一个简便的方法,等同于调用write()并接着调用flush() |
20、Netty 提供的内置传输
名称 |
包 |
描述 |
NIO |
io.netty.channel.socket.nio |
使用java.nio.channels 包作为基础 — 基于选择器的方式 |
Epoll |
io.netty.channel.epoll |
由JNI驱动的epoll()和非租塞IO。这个传输支持只有在Linux上可用的多种特性, (如:so_reuseport, 比NIO传输更快,而且是完全非租塞的) |
OIO |
io.netty.channel.socket.oio |
使用java.net 包作为基础 — 使用阻塞流 |
Local |
io.netty.channel.local |
可以在VM内部通过管道进行通信的本地传输 |
Embedded |
io.netty.channel.embedded |
Embedded传输,允许使用ChannelHandler而又不需要一个真正的基于网络的传输。 这在测试你的ChannelHandler实现时非常有用 |
21、零拷贝
一种目前只有在使用NIO和Epoll传输时才可以使用的特性。
可以快速高效的将数据从文件系统移动到网络接口,且不需要将其从内核空间复制到用户空间。在FTP或HTTP协议中可以显著地提升性能
注:只能传输文件的原始内容。可以传输加密的文件,不可以传输加密的数据或压缩的文件。
22、应用程序最佳传输
应用程序的需求 |
推荐的传输 |
非阻塞代码库或者一个常规的起点 |
NIO(或者LInux上使用epoll) |
阻塞代码库 |
OIO |
在同一个JVM内部的通信 |
Local |
测试 ChannelHandler 的实现 |
Embedded |
23、ByteBuf API 的优点
l 可以被用户自定义的缓冲区类型扩展
l 通过内置的复合缓冲区类型实现了透明的零拷贝
l 容量可以按需增长(类似于JDK的StringBuffer)
l 在读写两种类型切换时不需要调用byteBuffer的flip()方法
l 读写使用了不同的索引
l 支持方法的链式调用
l 支持引用计数
l 支持池化
24、ByteBuffy类 — Netty 的数据容器
ByteBuf 维护了两个不同的索引:一个用于读取,一个用于写入。
ByteBuf 使用模式:
堆缓冲区 ByteBuf.hasArray() 为 true
直接缓冲区 ByteBuf.hasArray() 为 false
复合缓冲区 ByteBuf 的聚合视图,通过子类 CompositeByteBuf 实现
25、字节操作
随机访问索引:
ByteBuf 索引从0开始,最后一个索引为 capacity() – 1 。
例: byte b = byteBuf.getByte(i);
顺序访问索引:
0 – (已被读过的:可被丢弃的字节) ->readerIndex – (尚未被读的:可读字节) ->writeIndex – (可添加更多字节:可写字节) -> capacity
可丢弃字节:
调用 discardReadBytes() ,将可丢弃字节丢弃并回收空间到可写字节。(建议在内存宝贵时候调用)
可读字节:
ByteBuf 的可读字节分段存储实际数据。
名称以 read 或者 skip 开头的操作将增加已读字节数
可写字节:
可写字节分段 指一个拥有未定义内容的、写入就绪的内存区域。
任何以write开头的操作都将从当前的writeIndex处开始写数据,并将增加已经写入的字节数
索引管理:
mark(int readlimit) 将流中的当前位置标记为指定的值
reset() 将流重置到该位置
markReaderIndex() / markWriteIndex() 标记 ByteBuf 的 readerIndex 和WriteIndex
resetWriterIndex() / resetReaderIndex() 重置 ByteBuf 的 readerIndex 和WriteIndex
readerIndex(int) / writerIndex(int) 将索引移动到指定位置
clear() 将readerIndex 和writerIndex 都设置为0 且不会清除内存中的内容
查找操作:
Netty 4.1 中 使用io.netty.util.ByteProcessor 接口下方法。 来确定指定值的索引
派生缓冲区:
为ByteBuf提供专门的方式呈现视图。例:duplicate() , slice() , slice(int, int) , Unpooled.unmodifiableBuffer(…) , order(ByteOrder) , readSlice(int). 方法返回新的ByteBuf实例,具有自己的读、写索引和标记索引。 派生换缓冲区修改内容,也会修改对应的源实例内容。
【ByteBuf复制:使用copy() 或者 copy(int, int) 方法,返回ByteBuf 拥有的独立数据副本。】
读、写操作:
get() 和 set() 操作,从给定的索引开始,保持索引不变。
read() 和 write() 操作,从给定的索引开始,会根据已经访问过的字节
get() 操作
名称 |
描述 |
getBoolean(int) |
返回给定索引处的 Bollean值 |
getByte(int) |
返回给定索引处的 字节 |
getUnsignedByte(int) |
将给定索引处的 无符号字节值作为short返回 |
getMedium(int) |
返回给定索引处的 24位的中等int值 |
getUnsignedMedium(int) |
返回给定索引处的 无符号的24位的中等 int 值 |
getInt(int) |
返回给定索引处的 int 值 |
getUnsignedInt(int) |
将给定索引处的 无符号 int 值作为 long 返回 |
getLong(int) |
返回给定索引处的 long 值 |
getShort(int) |
返回给定索引处的 short 值 |
getUnsignedShrt(int) |
将给定索引处的无符号 short 值作为 int 返回 |
getByte(int, …) |
将该缓冲区中从给定索引开始的数据传送到指定的目的地 |
set() 操作
名称 |
描述 |
setBoolean(int, boolean) |
设定给定索引处的 Boolean 值 |
setByte(int index, int value) |
设定给定索引处的 字节值 |
setMedium(int index, int value) |
设定给定索引处的 24位的中等 int 值 |
setInt(int index, int value) |
设定给定索引处的 int 值 |
setLong(int index, long value) |
设定给定索引处的 long 值 |
setShort(int index, int value) |
设定给定索引处的 short 值 |
read() 操作
名称 |
描述 |
readBoolean() |
返回当前 readerIndex 处的 Boolean, 并将readerIndex 增加 1 |
readByte() |
返回当前readerIndex 处的字节,并将readerIndex 增加 1 |
readUnsignedByte() |
将当前 readerIndex 处的无符号字节值作为short 返回,并将readerIndex 增加 1 |
readMedium() |
返回当前readerIndex 处的24位的中等int 值,并将readerIndex 增加 3 |
readUnsignedMedium() |
返回当前 readerIndex 处的 24位的无符号的中等int 值, 并将readerIndex 增加 3 |
readInt() |
返回当前 readerIndex 处的int 值,并将readerIndex增加 4 |
readUnsignedInt() |
将当前readerIndex处的无符号的int值作为long值返回, 并将readerIndex 增加 4 |
readLong() |
返回当前readerIndex 处的long值,并将readerIndex 增加 8 |
readShort() |
返回当前readerIndex 处的short 值,并将readerIndex 增加 2 |
readUnsignedShort() |
将当前 readerIndex 处无符号 short 值 作为 int 值返回,并将readerIndex 增加 2 |
readBytes( ByteBuf | byte [] destinatuion, int dstIndex [ , int length] ) |
将当前 ByteBuf 中 从当前 readerIndex 处 开始的数据传送到一个目标 ByteBuf 或者 byte[],从目标的dstIndex开始的位置。本地的readerIndex将被增加已经传输的字节数。 |
write() 操作
名称 |
描述 |
writeBoolean( boolean ) |
在当前 writeIndex 处写入一个Boolean ,并将 writeIndex 增加 1 |
writeByte( int ) |
在当前 writeIndex 处写入一个字节值,并将writeIndex 增加 1 |
writeMedium( int ) |
在当前 writeIndex 处写入一个中等的 int 值, 并将writeIndex 增加 3 |
writeInt ( int ) |
在当前 writeIndex 处写入一个 int 值,并将writeIndex 增加 4 |
writeLong ( long ) |
在当前 writeIndex 处写入一个 long 值,并将 writeIndex 增加 8 |
writeShort ( int ) |
在当前writeIndex 处写入一个 short 值, 并将 writeIndex 增加 2 |
writeBytes ( source ByteBuf | byte [] [ , int srcIndex , int length ] ) |
从 当前writeIndex 开始,传输来自于指定源的数据,如果提供了srcIndex 和 length, 则从 srcIndex 开始读取,并且处理长度为 length 的字节,当前 writeIndex 将会被增加所写入的字节数。 |
更多操作
名称 |
描述 |
isReadable() |
如果至少有一个字节可读取,返回 true |
isWritable() |
如果至少有一个字节可写入,返回 true |
readableByte() |
返回可被读取的字节数 |
writableBytes() |
返回可被写入的字节数 |
capacity() |
返回ByteBuf 可容纳的字节数, 此后,会尝试再次扩展,直到达到maxCapacity() |
maxCapacity() |
返回ByteBuf 可以容纳的最大字节数 |
hasArray() |
如果ByteBuf 由一个字节数组支撑,则返回 true |
array() |
如果ByteBuf 由一个字节数组支撑则返回该数组,否则,它将抛出一个 UnsupportedOperationException 异常 |
26、ByteBufAllocator 池化和引用计数
池化:为了降低分配和释放内存的开销,可以分配任意类型的ByteBuf类型。
引用计数:通过某个对象持有的资源不在被其他对象引用时,释放该对象持有资源来 优化内存使用和性能的技术。
27、ChannelHandler
Channel 的生命周期状态
状态 |
描述 |
ChannelUnregistered |
Channel 已经被创建,但还未注册到EventLoop |
ChannelRegistered |
Channel 已经被注册到了EventLoop |
ChannelActive |
Channel 处于活动状态(已经连接到它的远程节点)。它现在可以接收和发送数据了 |
ChannelInactive |
Channel 没有连接到远程节点 |
ChannelHandler 的生命周期
状态 |
描述 |
handlerAdded |
当把 ChannelHandler 添加到 ChannelPipeline 中时被调用 |
handlerRemoved |
当从 ChannelPipeline 中移除 ChannelHandler 时被调用 |
exceptionCaught |
当处理过程中在 ChannelPipeline 中有错误时被调用 |
ChannelHandler 两个重要的子接口: ChannelInboundHandler 、 ChannelOutboundHandler
(1)ChannelInboundHandler 的实现重写 channelRead() 方法,负责显示地释放与池化 ByteBuf 内存。
Netty一个实用方法 — ReferenceCountUtil.release(msg);
或者 另一种简单方式:实用 SimpleChannelInboundHandler
(2)ChannelOutBoundHandler 接口
ChannelOutBoundHandler 功能在于 按需推迟操作或者事件。
ChannelOutboundHandler 中大部分方法都需要一个ChannelPromise 参数,在操作完成时得到通知。
28、资源管理
诊断潜在的资源泄露。 有四种检测级别
级别 |
描述 |
DISABLED |
禁用泄漏检测。只有在详尽的测试之后才应使用 |
SIMPLE |
使用1%的默认采样率检测并报告任何发现的泄露。这是默认级别,适合绝大部分情况。 |
ADVANCED |
使用默认的采样率,报告所发现的任何的泄露以及对应的消息被访问的位置 |
PARANOID |
类似于ADVANCED,但是其将会对每次(对消息的)访问都进行采样。这对性能将会有很大影响,在调试阶段使用 |
总之:如果消息被消费或者丢弃了,并且没有传递给ChannelPipeline 中的下一个ChannelOutboundHandler ,那么用户就有责任调用 ReferenceCountUtil.release()。 如果消息到达了实际传输层,当它被写入时,或者Channel关闭时,会自动释放。
29、ChannelPipeline 接口
每个新创建的 Channel 都将会被分配一个新的 ChannelPipeline 。这是永久性关联。
Netty 总是将 ChannelPipeline 的入站口作为头部,出站口作为尾部。
ChannelHandler 可以添加、删除、替换 其他的ChannelHandler,从而实时修改ChannelPipeline 布局。
名称 |
描述 |
addFirst addBefore addAfter addLast |
将一个ChannelHandler 添加到ChannelPipeline 中 |
remove |
将一个ChannelHandler 从 ChannelPipeline 中移除 |
replace |
将 ChannelPipeline 中的一个 ChannelHandler 替换为另一个ChannelHandler |
ChannelPipeline 用于访问 ChannelHandler 的操作
名称 |
描述 |
get |
通过类型或者名称返回 ChannelHandler |
context |
返回和ChannelHandler 绑定的 ChannelHandlerContext |
names |
返回ChannelPipeline 中所有 ChannelHandler 的名称 |
总结:
l ChannelPipeline 保存了与Channel 相关联的ChannelHandler;
l ChannelPipeline 可以根据需要,通过添加或者删除ChannelHandler 来动态地修改;
l ChannelPipeline 有着丰富的 API 用以被调用,以响应入站和出站事件。
30、ChannelHandlerContext 接口
ChannelHandlerContext 主要功能是管理它所关联的ChannelHandler 和在同一个 ChannelPipeline 中的其他 ChannelHandler 之间的交互。
如果调用 Channel 或者ChannelPipeline 上的方法,流程将沿着ChannelPipeline 进行传播。调用ChannelHandlerContext 上的相同方法,流程从关联的ChannelHandler 开始,并且只会传播位于该 ChannelPipeline 中的下一个能够处理的该事件的 ChannelHandler。
注:重要 ChannelHandlerContext 和 ChannelHandler 之间关联(绑定)是永远不会改变的,所以缓存对它的引用是安全的。
相对于其他类的同名方法,ChannelHandlerContext 的方法将产生更短的事件流,可以用这个特定获得最大性能。
31、共享同一个 ChannelHandler
在多个 ChannelPipeline 中安装同一个ChannelHandler 的一个常见原因:用于收集跨域多个 Channel 的统计信息。
32、处理入站异常
l ChannelHandler.exceptionCaught()的默认将异常转发给 ChannelPipeline 中的下一个ChannelHandler;
l 如果异常到达ChannelPipeline 尾端,将会被记录为未被处理;
l 想要定义自定义的处理逻辑,需要重写 exceptionCaught() 方法。然后决定是否把异常传播出去。
33、处理出站异常
l 出站操作都返回一个ChannelFuture。注册到ChannelFuture 的ChannelFutureListener 将在操作完成时被通知操作是成功还是出错了。
l 所有 ChannelOutboundHandler 上的方法都会传入 ChannelPromise 。ChannelPromise 可以被分配用于异步通知的监听器。ChannelPromise 还具有提供立即通知的可写方法。
34、ChannelPromise 的可写方法
通过调用 ChannelPromise 上的 setSuccess() 和 setFailure()方法,可使一个操作状态在 ChannelHandler 方法返回给调用者时即刻被感知到。
34、基本的线程池化
l 从池的空闲线程列表中选择一个 Thread,并且指派它去运行一个已提交的任务(一个Runnable的实现)
l 当任务完成时,将该Thread返回给该列表,使其可被重用。
35、引导
引导一个应用程序指 对它进行配置,并使它运行起来的过程。
36、IllegalStateException
在引导过程中,调用bind() 或者connect() 方法钱,必须调用 group()、channel()或channelFactory()、handler() ; 如果没有调用,会导致 IllegalStateException 。对handler() 方法调用很重要,它需要配置好ChannelPipeline。
37、Netty应用程序一般准则
尽可能地重用EventLoop,以减少线程创建所带来的开销。
38、EventLoopGroup.shutdownGracefully() 关闭
处理任何挂起的事件和任务,并且随后释放所有活动的线程。
39、编码器、解码器
编码器:将消息转换为适合于传输的格式(例:字节流)。处理出站数据
解码器:将网络字节流转回应用程序的消息格式。处理入站数据
40、ByteToMessageDecoder API
方法 |
描述 |
decode( ChannelHandlerContext ctx, ByteBuf in, List<Object> out) |
必须实现的唯一抽象方法。 方法被调用时传入一个包含传入数据的ByteBuf,和一个添加解码消息的List。 对方法的调用会重复进行,知道没有新元素被添加到List,或ByteBuf中没有更多可读取的字节。 如果List不为空,它的内容会被传递给ChannelPipeline中的下一个ChannelInboundHandler |
decodeLast( ChannelHandlerContext ctx, ByteBuf in, List<Object> out) |
简单调用decode()方法, 当Channel状态为非活动时,这个方法会被调用一次。 可以重写该方法已提供特殊处理 |
41、解码器中的引用计数
对于编码器和解码器。一旦消息被编码或解码,它就被ReferenceCountUtil.release(message) 调用自动释放。
如果需要保留,可以调用ReferenceCountUtil.retain(message)。将会增加该引用计数,防止消息被释放。
42、MessagetoMessageDecoder API
方法 |
描述 |
decode ( ChannelHandlerContext ctx, I msg, List<Object> out) |
每个需要被解码为另一种格式的入站消息来说,该方法都将被调用。 解码消息随后会传递给 ChannelPipeline中的下一个ChannelInboundHandler |
43、TooLongFrameException 类
由解码器在帧超出指定的大小限制时抛出。
44、MessageToByteEncoder API
方法 |
描述 |
encode( ChannelHandlerContext ctx, I msg, ByteBuf out) |
唯一抽象方法,被调用时传入该类编码为ByteBuf的出站消息,该消息随后会被转发给ChannelPipeline中的下一个ChannelOutboundHandler |
45、ByteToMessageCodec API
方法名称 |
描述 |
decode( ChannelHandlerContext ctx, ByteBuf in, List<Object>) |
只要有字节可以被消费,这个方法就将被调用。它将入站ByteBuf 转换为指定的消息格式,并将其转发给ChannelPipeline 中的下一个ChannelInboundHandler |
decodeLast( ChannelHandlerContext ctx, ByteBuf in, List<Object> out) |
这个方法默认实现委托给decode()方法。在Channel状态变为非活动时被调用一次。可以被重写以实现特殊处理。 |
encode( ChannelHandlerContext ctx, I msg, ByteBuf out) |
对每个将被编码并写入出站ByteBuf的消息来说,这个方法都会被调用。 |
46、MessageToMessageCodec 的方法
方法名称 |
描述 |
protected abstract decode( ChannelHandlerContext ctx, INBOUND_IN msg, List<Object> out) |
传入INBOUND_IN 类型的消息。并把它解码为OUTBOUND_IN 类型的消息, 消息被转发给ChannelPipeline中的下一个ChannelInboundHandler |
protected abstract encode( ChannelHandlerContext ctx, OUTBOUND_IN msg, List<Object> out) |
对每个OUTBOUND_IN 类型的消息,该方法都被调用。消息会被编码为INBOUND_IN 类型的消息, 然后转发给ChannelPipeline中的下一个ChannelOutboundHandler |
47、SshHandler 的方法
方法名称 |
描述 |
setHandshakeTimeout (long , TimeUnit) setHandshakeTimeoutMillis (long) getHandshakeTimeoutMillis () |
设置和获取超市事件,超时后,握手ChannelFuture 将会被通知失败 |
setCloseNotifyTimeout (long, TimeUnit) setCloseNotifyTimeoutMillis (long) getCloseNotifyTimeoutMillis () |
设置和获取超时时间,超时后,将会触发一个关闭通知并关闭连接。同时会导致通知该ChannelFuture 失败 |
handshakeFuture() |
返回一个在握手完成后将会得到通知的ChannelFuture,如果握手前已经执行过,则返回包含了先前握手结果的ChannelFuture |
close() close(ChannelPromise) close(ChannelHandlerContext, ChannelPromise) |
发送 close_notify 以请求关闭并销毁底层的SslEngine |
48、用于空闲链接以及超时的ChannelHandler
名称 |
描述 |
IdleStateHandler |
当链接空闲时间太长,将触发一个IdleStateEvent 事件。然后,可以通过 ChannelInboundHandler中重写userEventTriggered()方法来处理该 IdleStateEvent 事件 |
ReadTimeoutHandler |
如果指定时间间隔内没收到任何入站数据,则抛出一个ReadTimeoutException 并关闭对应Channel。可以重写ChannelHandler中的exceptionCaught()方法检测该事件 |
WriteTimeoutHandler |
如果指定时间间隔内没有任何出站数据写入,则抛出WriteTimeoutExceptoin 并关闭对应Channel。可以重写ChannelHandler 的exceptionCaught()方法检测该事件 |
49、处理基于分隔符的协议和基于长度的协议的解码器
名称 |
描述 |
DelimiterBasedFrameDecoder |
使用任何由用户提供的分隔符来提取帧的通用解码器 |
LineasedFrameDecoder |
提取由行尾符(\n 或者 \r\n)分割的帧的解码器。这个解码器比DelimiterBaseFrameDecoder 更快 |
名称 |
描述 |
FixedLengthFrameDecoder |
提取在调用构造函数时指定的定长帧 |
LengthFieldBaseFrameDecoder |
根据编码进帧头部中的长度值提取帧; 该字段的偏移量以及长度在构造函数中指定 |
50、ChunkedWriteHandler
需要将数据从文件系统复制到用户内存中时,使用 ChunkedWriteHandler ,它支持异步写大型数据流,且不会导致大量的内存消耗。
51、JDK序列化编解码器
名称 |
描述 |
CompatibleObjectDecoder |
和使用JDK序列化的 非基于Netty的 远程节点 进行互操作的解码器 |
CompatibleObjectEncode |
和使用JDK序列化的 非基于Netty的 远程节点 进行互操作的编码器 |
ObjectDecoder |
构建于JDK 序列化之上的使用自定义的序列化来解码的解码器; 当没有其他的外部依赖时,它提供了速度上的改进。否则其他序列化更可取 |
ObjectEncoder |
构建于JDK序列化之上的使用自定义的序列化来编码的编码器; 当没有其他的外部依赖时,它提供了速度上的改进。否则其他序列化更可取 |
52、JBoss Marshalling 编解码器
名称 |
描述 |
CompatibleMarchallingDecoder CompatibleMarshallingEncoder |
与只使用JDK序列化的远程节点兼容 |
MarshallingDecoder MarshallingEncoder |
适用于使用JBoss Marshalling 的节点。这些类必须一起使用 |
53、Protobuf 编解码器
名称 |
描述 |
ProtobufDecoder |
使用 protobuf 对消息进行解码 |
ProtobufEncoder |
使用 protobuf 对消息进行编码 |
ProtobufVarint32FrameDecoder |
根据消息中的Google Protocol Buffer 的 “Base 128 Varints” 整型长度字段值动态地分割所接收到的ByteBuf |
ProtobufVarint32LengthFieldPrepender |
向ByteBuf 前追加一个Google Protocal Buffer 的“Base 128 Varints” 整型的长度字段值 |