Netty分布式行解码器逻辑源码解析

网友投稿 284 2022-08-17


Netty分布式行解码器逻辑源码解析

目录行解码器LineBasedFrameDecoder首先看其参数我们跟到重载的decode方法中我们看findEndOfLine(buffer)方法

前文传送门:Netty分布式解码器读取数据不完整的逻辑剖析

这一小节了解下行解码器LineBasedFrameDecoder, 行解码器的功能是一个字节流, 以\r\n或者直接以\n结尾进行解码, 也就是以换行符为分隔进行解析

同样, 这个解码器也继承了ByteToMessageDecoder

行解码器LineBasedFrameDecoder

首先看其参数

//数据包的最大长度, 超过该长度会进行丢弃模式

private final int maxLength;

//超出最大长度是否要抛出异常

private final boolean failFast;

//最终解析的数据包是否带有换行符

private final boolean stripDelimiter;

//为true说明当前解码过程为丢弃模式

private boolean discarding;

//丢弃了多少字节

private int discardedBytes;

其中的丢弃模式, 我们会在源码中看到其中的含义

我们看其decode方法

protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {

Object decoded = decode(ctx, in);

if (decoded != null) {

out.add(decoded);

}

}

这里的decode方法和我们上一小节分析的decode方法一样, 调用重载的decode方法, 并将解码后的内容放到out集合中

我们跟到重载的decode方法中

protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {

//找这行的结尾

final int eol = findEndOfLine(buffer);

if (!discarding) {

if (eol >= 0) {

final ByteBuf frame;

//计算从换行符到可读字节之间的长度

final int length = eol - buffer.readerIndex();

//拿到分隔符长度, 如果是\r\n结尾, 分隔符长度为2

final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;

//如果长度大于最大长度

if (length > maxLength) {

//指向换行符之后的可读字节(这段数据完全丢弃)

buffer.readerIndex(eol + delimLength);

//传播异常事件

fail(ctx, length);

return null;

}

//如果这次解析的数据是有效的

//分隔符是否算在完整数据包里

//true为丢弃分隔符

if (stripDelimiter) {

//截取有效长度

frame = buffer.readRetainedSlice(length);

//跳过分隔符的字节

buffer.skipBytes(delimLength);

} else {

//包含分隔符

frame = buffer.readRetainedSlice(length + delimLength);

}

return frame;

} else {

//如果没找到分隔符(非丢弃模式)

//可读字节长度

final int length = buffer.readableBytes();

//如果朝超过能解析的最大长度

if (length > maxLength) {

//将当前长度标记为可丢弃的

discardedBytes = length;

//直接将读指针移动到写指针

buffer.readerIndex(buffer.writerIndex());

//标记为丢弃模式

discarding = true;

//超过最大长度抛出异常

if (failFast) {

fail(ctx, "over " + discardedBytes);

}

}

//没有超过, 则直接返回

return null;

}

} else {

//丢弃模式

if (eol >= 0) {

//找到分隔符

//当前丢弃的字节(前面已经丢弃的+现在丢弃的位置-写指针)

final int length = discardedBytes + eol - buffer.readerIndex();

//当前换行符长度为多少

final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;

//读指针直接移到换行符+换行符的长度

buffer.readerIndex(eol + delimLength);

//当前丢弃的字节为0

discardedBytes = 0;

//设置为未丢弃模式

discarding = false;

//丢弃完字节之后触发异常

if (!failFast) {

fail(ctx, length);

}

} else {

//累计已丢弃的字节个数+当前可读的长度

discardedBytes += buffer.readableBytes();

//移动

buffer.readerIndex(buffer.writerIndex());

}

return null;

}

}

 final int eol = findEndOfLine(buffer)

这里是找当前行的结尾的索引值, 也就是\r\n或者是\n:

6-3-1

图中不难看出, 如果是以\n结尾的, 返回的索引值是\n的索引值, 如果是\r\n结尾的, 返回的索引值是\r的索引值

我们看findEndOfLine(buffer)方法

private static int findEndOfLine(final ByteBuf buffer) {

//找到/n这个字节

int i = buffer.forEachByte(ByteProcessor.FIND_LF);

//如果找到了, 并且前面的字符是-r, 则指向/r字节

if (i > 0 && buffer.getByte(i - 1) == '\r') {

i--;

}

return i;

}

这里通过一个forEachByte方法找\n这个字节, 如果找到了, 并且前面是\r, 则返回\r的索引, 否则返回\n的索引

回到重载的decode方法中:

if (!discarding) 判断是否为非丢弃模式, 默认是就是非丢弃模式, 所以进入if中

if (eol >= 0) 如果找到了换行符, 我们看非丢弃模式下找到换行符的相关逻辑:

final ByteBuf frame;

final int length = eol - buffer.readerIndex();

final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;

if (length > maxLength) {

buffer.readerIndex(eol + delimLength);

fail(ctx, length);

return null;

}

if (stripDelimiter) {

frame = buffer.readRetainedSlice(length);

buffer.skipBytes(delimLength);

} else {

frame = buffer.readRetainedSlice(length + delimLength);

}

return frame;

首先获得换行符到可读字节之间的长度, 然后拿到换行符的长度, 如果是\n结尾, 那么长度为1, 如果是\r结尾, 长度为2

if (length > maxLength) 带表如果长度超过最大长度, 则直接通过 readerIndex(eol + delimLength) 这种方式, 将读指针指向换行符之后的字节, 说明换行符之前的字节需要完全丢弃

6-3-2

丢弃之后通过fail方法传播异常, 并返回null

继续往下看, 走到下一步, 说明解析出来的数据长度没有超过最大长度, 说明是有效数据包

if (stripDelimiter) 表示是否要将分隔符放在完整数据包里面, 如果是true, 则说明要丢弃分隔符, 然后截取有效长度, 并跳过分隔符长度

将包含分隔符进行截取

以上就是非丢弃模式下找到换行符的相关逻辑

我们再看非丢弃模式下没有找到换行符的相关逻辑, 也就是非丢弃模式下,  if (eol >= 0) 中的else块:

final int length = buffer.readableBytes();

if (length > maxLength) {

discardedBytes = length;

buffer.readerIndex(buffer.writerIndex());

discarding = true;

if (failFast) {

fail(ctx, "over " + discardedBytes);

}

}

return null;

首先通过 final int length = buffer.readableBytes() 获取所有的可读字节数

然后判断可读字节数是否超过了最大值, 如果超过最大值, 则属性discardedBytes标记为这个长度, 代表这段内容要进行丢弃

6-3-3

buffer.readerIndex(buffer.writerIndex()) 这里直接将读指针移动到写指针, 并且将discarding设置为true, 就是丢弃模式

如果可读字节没有超过最大长度, 则返回null, 表示什么都没解析出来, 等着下次解析

我们再看丢弃模式的处理逻辑, 也就是 if (!discarding) 中的else块:

首先这里也分两种情况, 根据 if (eol >= 0) 判断是否找到了分隔符, 我们首先看找到分隔符的解码逻辑:

final int length = discardedBytes + eol - buffer.readerIndex();

final int delimLength = buffer.getByte(eol) == '\r'?ojZdqkG 2 : 1;

buffer.readerIndex(eol + delimLength);

discardedBytes = 0;

discarding = false;

if (!failFast) {

fail(ctx, length);

}

如果找到换行符, 则需要将换行符之前的数据全部丢弃掉

6-3-4

final int length = discardedBytes + eol - buffer.readerIndex()

这里获得丢弃的字节总数, 也就是之前丢弃的字节数+现在需要丢弃的字节数

然后计算换行符的长度, 如果是\n则是1, \r\n就是2

buffer.readerIndex(eol + delimLength)

这里将读指针移动到换行符之后的位置

然后将discarding设置为false, 表示当前是非丢弃状态

我们再看丢弃模式未找到换行符的情况, 也就是丢弃模式下,  if (eol &gojZdqkGt;= 0) 中的else块:

discardedBytes += buffer.readableBytes();

buffer.readerIndex(buffer.writerIndex());

这里做的事情非常简单, 就是累计丢弃的字节数, 并将读指针移动到写指针, 也就是将数据全部丢弃

最后在丢弃模式下, decode方法返回null, 代表本次没有解析出任何数据

以上就是行解码器的相关逻辑

以上就是Netty分布式行解码器逻辑源码解析的详细内容,更多关于Netty分布式行解码器的资料请关注我们其它相关文章!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java实现线程安全单例模式的五种方式的示例代码
下一篇:Java超详细教你写一个网络购书系统案例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~