分析常用的两个FrameDecoder,LineBasedFrameDecoder和DelimiterBasedFrameDecoder
这两个都是extends ByteToMessageDecoder,如LineBasedFrameDecoder的属性:
/** Maximum length of a frame we're willing to decode. */
private final int maxLength;
/** Whether or not to throw an exception as soon as we exceed maxLength. */
private final boolean failFast;
private final boolean stripDelimiter;
/** True if we're discarding input because we're already over maxLength. */
private boolean discarding;
private int discardedBytes;
/** Last scan position. */
private int offset;
new LineBasedFrameDecoder(10000,true,true),第二个参数是stripDelimiter,第三个参数是failFast,顾名思义,第二个参数是最终报文去掉分割符,第三个参数是快速失败。下面测试一下第三个参数。
.childHandler(new ChannelInitializer<SocketChannel>() { // (4)
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast("frameDecoder", new LineBasedFrameDecoder(100,true,true)) //new LineBasedFrameDecoder(100))
.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8))
.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8))
.addLast("messageHandler",new LineEchoHandler());
}
})
首先是new LineBasedFrameDecoder(10000)),这时候客户端发送一个大报文2951,远超过了100,如果failfast是false,这个分割器会把2951这个报文全部读取,但是,一旦决定丢弃,只会记录要丢弃的长度,不会持有内容,所以就算遇到超长的报文,也不会占据内存。
现在有另一个疑问,如果failfast为true,会怎么样?
如果是
new LineBasedFrameDecoder(100,true,true),那么这个报文依然会被全部丢弃,只是会快速的抛出异常,而且,如果抛出异常但是不关闭连接的话,会多次读取将这个有问题的报文丢弃掉,做到不影响下一帧报文。
注意读取大报文的时候,netty并不是一开始就分配一个很大的directbuffer,而是从小到大逐步递增。
AbstractNioByteChannel.read()方法中,会使用allocHandle.allocate(allocator)分配一个bytebuf,如果这个bytebuf在这次读取中不够用,会增大进行下次读取。读取完成后还会记录这次读取的字节数目,以便扩充的时候决定扩充多大。