前面說到,LengthFieldBasedFrameDecoder類是我們最常用的一個粘包拆包工具,能幫我們解決95%以上的粘包拆包問題。
LengthFieldBasedFrameDecoder類能夠解決的最復(fù)雜的數(shù)據(jù)包結(jié)構(gòu)類似如下:

從上圖可以看出,這種協(xié)議類似“包頭1 + 包體長度 + 包頭2 + 包體”這種結(jié)構(gòu)。
這種協(xié)議結(jié)構(gòu)已經(jīng)很復(fù)雜了,但現(xiàn)實往往不盡如人意,比如有如下形式的數(shù)據(jù)協(xié)議:

這種數(shù)據(jù)協(xié)議結(jié)構(gòu)類似于“包頭 + 包體長度 + 包體 +包尾”。
很明顯,這種帶“包尾”的協(xié)議結(jié)構(gòu),就是LengthFieldBasedFrameDecoder類不能解決的。
因此,我們必須自定義這種協(xié)議的LengthFieldBasedFrameDecoder類。
我們通過對LengthFieldBasedFrameDecoder類進行預(yù)研,發(fā)現(xiàn)我們自定義的LengthFieldBasedFrameDecoder類不能夠通過繼承LengthFieldBasedFrameDecoder類來解決問題,只能把LengthFieldBasedFrameDecoder類的代碼拷貝過來修改。
開始的代碼如下:
public class CashboxDataLengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
private static final int TAIL_LENGTH = 7;
private final ByteOrder byteOrder;
private final int maxFrameLength;
private final int lengthFieldOffset;
private final int lengthFieldLength;
private final int lengthFieldEndOffset;
private final int lengthAdjustment;
private final int initialBytesToStrip;
private final boolean failFast;
private boolean discardingTooLongFrame;
private long tooLongFrameLength;
private long bytesToDiscard;
所有的粘包拆包解碼器類,都需要繼承ByteToMessageDecoder類。
再往下,就是我們自定義的包尾長度-private static final int TAIL_LENGTH = 7;,后面都是拷貝LengthFieldBasedFrameDecoder類的代碼。
最后的修改在decode方法里:
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (discardingTooLongFrame) {
discardingTooLongFrame(in);
}
if (in.readableBytes() < lengthFieldEndOffset) {
return null;
}
int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset;
long frameLength = getUnadjustedFrameLength(in, actualLengthFieldOffset, lengthFieldLength, byteOrder);
if (frameLength < 0) {
failOnNegativeLengthField(in, frameLength, lengthFieldEndOffset);
}
/**
* 增加的代碼,加上尾部的長度,作為內(nèi)容的長度。
*/
frameLength += TAIL_LENGTH;
frameLength += lengthAdjustment + lengthFieldEndOffset;
可以看到,僅有的改動就在內(nèi)容長度-frameLength上,將這個長度再加上包尾的長度,就可以了。
后面的代碼,就都是考慮原LengthFieldBasedFrameDecoder類的代碼了,在此就不再多說了。