我们之前介绍了Netty的解码器ByteToMessageDecoder,那Netty具体的解码器有哪几种呢,Netty提供的解码器主要有以下几个:
DelimiterBasedFrameDecoder 解决TCP的粘包解码器
StringDecoder 消息转成String解码器
LineBasedFrameDecoder 自动完成标识符分隔解码器
FixedLengthFrameDecoder 固定长度解码器,二进制
Base64Decoder base64 解码器
下面我们就来说说DelimiterBasedFrameDecoder这个类。
在此之前先说下tcp通信的问题, 当客户端向服务端发送了一个大的数据包时(如600M),TCP几乎不会一次把这个包完整的发送到服务端,TCP分把这个包分包,分几次发给服务端,至于TCP要分多少次,这是不可预测的。那怎么处理这种问题呢?这就需要用到我们介绍的DelimiterBasedFrameDecoder了。DelimiterBasedFrameDecoder是以换行符作为分割符,对数据进行解码。也就是\n和\r\n。好了,我们来看看decode方法是怎么实现的
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
if (lineBasedDecoder != null) {
return lineBasedDecoder.decode(ctx, buffer);
}
// Try all delimiters and choose the delimiter which yields the shortest frame.
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;
}
}
if (minDelim != null) {
int minDelimLength = minDelim.capacity();
ByteBuf frame;
if (discardingTooLongFrame) {
// We've just finished discarding a very large frame.
// Go back to the initial state.
discardingTooLongFrame = false;
buffer.skipBytes(minFrameLength + minDelimLength);
int tooLongFrameLength = this.tooLongFrameLength;
this.tooLongFrameLength = 0;
if (!failFast) {
fail(tooLongFrameLength);
}
return null;
}
if (minFrameLength > maxFrameLength) {
// Discard read frame.
buffer.skipBytes(minFrameLength + minDelimLength);
fail(minFrameLength);
return null;
}
if (stripDelimiter) {
frame = buffer.readRetainedSlice(minFrameLength);
buffer.skipBytes(minDelimLength);
} else {
frame = buffer.readRetainedSlice(minFrameLength + minDelimLength);
}
return frame;
} else {
if (!discardingTooLongFrame) {
if (buffer.readableBytes() > maxFrameLength) {
// Discard the content of the buffer until a delimiter is found.
tooLongFrameLength = buffer.readableBytes();
buffer.skipBytes(buffer.readableBytes());
discardingTooLongFrame = true;
if (failFast) {
fail(tooLongFrameLength);
}
}
} else {
// Still discarding the buffer since a delimiter is not found.
tooLongFrameLength += buffer.readableBytes();
buffer.skipBytes(buffer.readableBytes());
}
return null;
}
}
简单的说,就是DelimiterBasedFrameDecoder有两种工作模式,丢弃模式和非丢弃模式。当在丢弃模式下,大于一个数据包的数据会被丢弃,直接skip对应的字节。在非丢弃模式下,则是存在容器里,然后等待下一个数据包到来的时候,拼接到一起。数据解析完成后,再把解码后的对象传递给下个节点。
DelimiterBasedFrameDecoder就分析到这里了。
网友评论