接上篇:Netty学习——高级篇1 拆包 、粘包与编解码技术,本章继续介绍Netty的其他解码器
1 DelimiterBasedFrameDecoder分隔符解码器
DelimiterBasedFrameDecoder 分隔符解码器是按照指定分隔符进行解码的解码器,通过分隔符可以将二进制流拆分成完整的数据包。回车换行符解码器实际上是一种特殊的DelimiterBasedFrameDecoder解码器。
分隔符解码器在实际工作中有很广泛的应用,很多简单的文本私有协议都以特殊的分隔符作为消息结束的标识,特别是那些使用长连接的基于文本的私有协议。关于分隔符的指定,并非以Char或者String作为构造参数,而是以Bytebuf。下面就结合实际例子给出它的用法。例如消息是以“$_”作为分隔符,服务端或者客户端初始化ChannelPipeline的代码实例如下:
ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes()); ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter)); ch.pipeline().addLast(new StringDecoder());
DelimiterBasedFrameDecoder同样继承了ByteToMessageDecoder并重写了decode方法,来看其中的一个构造方法。
public DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf delimiter) { this(maxFrameLength, true, delimiter); }
其中,参数 maxFrameLength 代表最大长度,delimiter是个可变参数,可以支持多个分隔符进行解码。跟进decode方法。
@Override protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { Object decoded = decode(ctx, in); if (decoded != null) { out.add(decoded); } }
这里同样调用了重载的decode方法并将解析好的数据添加到集合List中,其父类就可以遍历Out,并将内容传播。重载的decode方法代码如下:
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
//行处理器(1)
if (lineBasedDecoder != null) {
return lineBasedDecoder.decode(ctx, buffer);
}
int minFrameLength = Integer.MAX_VALUE;
ByteBuf minDelim = null;
//找到最小长度的分隔符
for (ByteBuf delim: delimiters) {
//每个分隔符分隔的数据包长度
int frameLength = indexOf(buffer, delim);
if (frameLength >= 0 && frameLength < minFrameLength) {
minFrameLength = frameLength;
minDelim = delim;
}
}
//解码(3)
//已经找到分隔符
if (minDelim != null) {
int minDelimLength = minDelim.capacity();
ByteBuf frame;
//当前分隔符是否处于丢弃模式
if (discardingTooLongFrame) {
// 首先设置为非丢弃模式
discardingTooLongFrame = false;
//丢弃
buffer.skipByte