Netty解码器报错:XXXDecoder.decode() did not read anything but decoded a message.
从字面意思来看,就是说没有读取任何数据,但是却解析出来了一个对象。
1、问题引出
在写自定义的基于String的解码器的时候,在使用该解码器进行解码的时候会抛出这个异常。
- 对应的解码器代码很简单,就是将ByteBuf转化为一个字符串,然后添加到list中,供后面的handler进行处理。
- 编码器代码也很简单,就是将字符串变成一个byte数组,写到ByteBuf中,供后面的handler进行处理。
2、ByteToMessageDecoder源码解析
当有数据到来的时候,会调用handler的channelRead方法,代码逻辑很简单大概分为三步:
- 读取字节流,累加字节流
- 将读取到的字节流交由子类的decoder方法解析,也就是我们自定义的解码器
- 将解析出来的对象继续向下传播
其中在调用子类decoder方法的时候,会有这么一段判断逻辑:
- 记录一下在解析之前list里面的对象数量。
- 记录一下解析之前字节流里面可读的字节数。
- 然后调用子类的解析方法
- 调用之后,list里面的对象和之前的相等,说明没有解析出对象,此时分两种情况,一种没有读取到数据,另一种解析出部分数据但不够构成一个对象
- 最后就来到异常抛出的地方,也就是解析出来了对象,但是bytebuf可读的字节容量和解析之前可读的字节数是相等的,换句话说就是明明解析出来了对象,但是没有读取走数据,因此这里会抛出异常。
那么为什么会进这个if呢?看自定义的解码器,只是单纯的将byteBuf转换成了一个String,byteBuf的readIndex并没有任何移动,因此byteBuf可读的字节数量在解析前后是相等的。
3、问题解决
知道了异常抛出的原因,这下解决它还是很简单的,只需要让byteBuf的readindex索引随读取的数据向前移动即可,因此可以有两种解决方式:
- 将buteBuf里面的数据读取到放在一个byte数组中,然后,将byte数组转化为String向下传播,这样byteBuf的readIndex会向前移动的。
- 继续采用之前的方式,但是读取完之后,人为让readindex向前移动:
-
采用这两种方式,均可以完美解决问题。