扫描下方二维码或者微信搜索公众号
菜鸟飞呀飞
,即可关注微信公众号,阅读更多Spring源码分析
和Java并发编程
文章。
前言
在上一篇文章中,只分析了 netty 如何通过编解码器解决了 TCP 粘包、半包的问题,没有具体分析解码器是如何来对数据进行解码的,今天本文将具体分析这些解码器的工作原理。
netty 为我们提供了几个十分常用的解码器,这几个解码器几乎能满足我们所有的场景,这几个解码器根据难易程度,从上到下,如下表所示。
FixedLengthFrameDecoder(基于固定长度的解码器)
LineBasedFrameDecoder (基于行分隔符的解码器)
DelimiterBasedFrameDecoder (基于自定义分割符的解码器)
LengthFieldBasedFrameDecoder (基于长度字段的解码器)
前三个解码器比较简单,也容易理解,最后一个解码器相对而言比较复杂,也不容易理解,但它能满足的场景却是最多的。由于前三个解码器比较简单,因此将它们的源码放在一篇文章中分析,也就是今天本文的主要内容。最后一个解码器的源码将在后面一篇文章中单独分析。
FixedLengthFrameDecoder
根据类名,翻译过来就能知道这是一个基于固定长度的解码器,什么意思呢?就是在初始化这个解码器时,指定一个 int 类型的数值:frameLength,后面在解码时,每当读到 frameLength 长度的字节时,就解码出一个数据对象。例如:当发送方发送了四次数据,分别是 A、BC、DEFG、HI,一共 9 个字节,如果我们指定解码器的固定长度 frameLength = 3,那么就表示每 3 个字节解一次码,那么解码出来的结果结果就是:ABC、DEF、GHI。
+---+----+------+----+ +-----+-----+-----+
| A | BC | DEFG | HI | -> | ABC | DEF | GHI |
+---+----+------+----+ +-----+-----+-----+
基于固定长度的解码器的源码和注释如下,比较简答,就不做展开分析了,参考源码中的注释即可。
public class FixedLengthFrameDecoder extends ByteToMessageDecoder {
// 表示每次解码多长的数据
private final int frameLength;
public FixedLengthFrameDecoder(int frameLength) {
checkPositive(frameLength, "frameLength");
// 指定每次解码的字节数
this.frameLength = frameLength;
}
@Override
protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// 解码
Object decoded = decode(ctx, in);
// 如果解码出来的数据对象不为空,就将其保存到out这个集合中
if (decoded != null) {
out.add(decoded);
}
}
protected Object decode(
@SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception {
// 如果可读取的数据小于每次解码的长度,那就直接返回null
if (in.readableBytes() < frameLength) {
return null;
} else {
// 读取指定长度的字节数据,然后返回
return in.readRetainedSlice(frameLength);
}
}
}
LineBaseFrameDecoder
LineBaseFrameDecoder是基于行分割符的解码器。什么意思呢?就是每当读到行分隔符(\n 或者\r\n)的时候,就解析出一个数据对象。例如如下示例。
+---+-------+----------+------+ +-----+-----+</