Netty 解码器-ReplayingDecoder
它是ByteToMessageDecoder的一种变体,支持在阻塞I/O中实现非阻塞解码器。它不需要像 ByteToMessageDecoder 在decode()方法中需要检查所需字节的可用性。
ReplayingDecoder 是如何运作的?
看一个例子:
//ByteToMessageDecoder实现:
public class IntegerHeaderFrameDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx,ByteBuf buf, List<Object> out) throws Exception {
if (buf.readableBytes() < 4) {
return;
}
buf.markReaderIndex();
int length = buf.readInt();
if (buf.readableBytes() < length) {
buf.resetReaderIndex();
return;
}
out.add(buf.readBytes(length));
}
}
// 使用ReplayingDecoder简化如下:
public class IntegerHeaderFrameDecoder
extends ReplayingDecoder<Void> {
protected void decode(ChannelHandlerContext ctx,ByteBuf buf, List<Object> out) throws Exception {
out.add(buf.readBytes(buf.readInt()));
}
}
在IntegerHeaderFrameDecoder 类中,调用 buf.readInt()时会有两种情况:
- 缓冲区中有4个或更多字节,它将按预期返回整数index。
- 缓冲区中不足4个字节,将会引发
Error并将控制权返回给ReplayingDecoder,当ReplayingDecoder捕获到Error,那么它会将缓冲区的readerIndex倒回到“初始”位置(即缓冲区的开头),并在缓冲区接收到更多数据时再次调用decode(..) 方法。
以简单为代价,ReplayingDecoder 可能会多次调用 decode() 方法来解码某个消息,这会有性能损失。
使用checkpint(T)方法提高性能
幸运的是,可以使用checkpoint()方法可以显著提高解码器性能。checkpoint()更新缓冲区的readerIndex位置倒回到您调用checkpoint()方法的最后一个位置。
管理解码器状态最简单的方法是创建一个代表解码器当前状态的 Enum 类型,每次状态改变时,就调用 checkpoint(T)。
public enum MyDecoderState {
READ_LENGTH,
READ_CONTENT;
}
public class IntegerHeaderFrameDecoder
extends ReplayingDecoder<MyDecoderState> {
private int length;
public IntegerHeaderFrameDecoder() {
// Set the initial state.
super(MyDecoderState.READ_LENGTH);
}
@Override
protected void decode(ChannelHandlerContext ctx,ByteBuf buf, List<Object> out) throws Exception {
switch (state()) {
case READ_LENGTH:
length = buf.readInt();
checkpoint(MyDecoderState.READ_CONTENT);
case READ_CONTENT:
ByteBuf frame = buf.readBytes(length);
checkpoint(MyDecoderState.READ_LENGTH);
out.add(frame);
break;
default:
throw new Error("Shouldn't reach here.");
}
}
}

浙公网安备 33010602011771号