圖片.png
圖片.png
Q
- 解碼器抽象解碼過程?
- netty提供哪些拆箱即用的解碼器?解碼器基類與常見解碼器解析
一、ByteToMessageDecoder解碼步驟
- **累加字節(jié)流
設(shè)置first為cumulation是否為空,累加器為空表賦值為讀進(jìn)來的ByteBuf對象,累加器非空調(diào)用cumulator的cumulate()方法通過ByteBuffer的writeBytes()方法把當(dāng)前累加器里面的數(shù)據(jù)和讀進(jìn)來的數(shù)據(jù)進(jìn)行累加 - 調(diào)用子類的decode方法進(jìn)行解析
調(diào)用callDecode()方法將累加器數(shù)據(jù)解析到的對象放到CodecOutputList向下進(jìn)行傳播,循環(huán)判斷累加器里面是否有數(shù)據(jù),通過調(diào)用fireChannelRead()方法向下進(jìn)行事件傳播,調(diào)用decode()方法ByteBuf解碼根據(jù)不同協(xié)議子類的解碼器把當(dāng)前讀到的所有數(shù)據(jù)即累加器里面的數(shù)據(jù)取出二進(jìn)制數(shù)據(jù)流解析放進(jìn)CodecOutputList - 將解析到的ByteBuf向下傳播
調(diào)用fireChannelRead()方法循環(huán)遍歷CodecOutputList通過事件傳播機(jī)制ctx.fireChannelRead()調(diào)用CodecOutputList的getUnsafe()方法獲取ByteBuf把解析到的ByteBuf對象向下進(jìn)行傳播
ByteToMessageDecoder.channelRead
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof ByteBuf) {//基于ByteBuf解碼
CodecOutputList out = CodecOutputList.newInstance();
try {
ByteBuf data = (ByteBuf) msg;
first = cumulation == null;
if (first) {
cumulation = data;//初始化cumulation
} else {
cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);//累加
}
callDecode(ctx, cumulation, out);//解析cumulation中ByteBuf到OutputList
} catch (DecoderException e) {
throw e;
} catch (Throwable t) {
throw new DecoderException(t);
} finally {
if (cumulation != null && !cumulation.isReadable()) {
numReads = 0;
cumulation.release();
cumulation = null;
} else if (++ numReads >= discardAfterReads) {
// We did enough reads already try to discard some bytes so we not risk to see a OOME.
// See https://github.com/netty/netty/issues/4275
numReads = 0;
discardSomeReadBytes();
}
int size = out.size();
decodeWasNull = !out.insertSinceRecycled();
fireChannelRead(ctx, out, size);//解析出的數(shù)據(jù)outlist,向后傳播
out.recycle();//outlist回收
}
} else {
ctx.fireChannelRead(msg);
}
}
cumulator.cumulate
public static final Cumulator MERGE_CUMULATOR = new Cumulator() {
@Override
public ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in) {
final ByteBuf buffer;
if (cumulation.writerIndex() > cumulation.maxCapacity() - in.readableBytes()
|| cumulation.refCnt() > 1 || cumulation.isReadOnly()) {
buffer = expandCumulation(alloc, cumulation, in.readableBytes());//cumulation擴(kuò)容
} else {
buffer = cumulation;
}
buffer.writeBytes(in);
in.release();
return buffer;
}
};
callDecode
protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
try {
while (in.isReadable()) {//如果累加器還有數(shù)據(jù)
int outSize = out.size();
if (outSize > 0) {//如果outputlist有數(shù)據(jù),則向后傳播,并清空
fireChannelRead(ctx, out, outSize);
out.clear();
if (ctx.isRemoved()) {
break;
}
outSize = 0;
}
int oldInputLength = in.readableBytes();
decodeRemovalReentryProtection(ctx, in, out);
if (ctx.isRemoved()) {
break;
}
if (outSize == out.size()) {//說明size沒變化,沒解析到數(shù)據(jù)
if (oldInputLength == in.readableBytes()) {
break;
} else {
continue;
}
}
if (oldInputLength == in.readableBytes()) {
throw new DecoderException(
StringUtil.simpleClassName(getClass()) +
".decode() did not read anything but decoded a message.");
}
if (isSingleDecode()) {
break;
}
}
} catch (DecoderException e) {
throw e;
} catch (Throwable cause) {
throw new DecoderException(cause);
}
}
final void decodeRemovalReentryProtection(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
throws Exception {
decodeState = STATE_CALLING_CHILD_DECODE;
try {
decode(ctx, in, out);//抽象方法,子類實(shí)現(xiàn),解析后對象放在out里
} finally {
boolean removePending = decodeState == STATE_HANDLER_REMOVED_PENDING;
decodeState = STATE_INIT;
if (removePending) {
handlerRemoved(ctx);
}
}
}
二、基于固定長度解碼器分析FixedLengthFrameDecoder
基于固定長度解碼器FixedLengthFrameDecoder成員變量frameLength表示固定長度,解碼器以多少長度分割解析,構(gòu)造方法傳參frameLength賦值給frameLength保存。
調(diào)用decode()方法解析累加器數(shù)據(jù)添加到CodecOutputList,判斷累加器可讀字節(jié)是否小于frameLength,小于返回空表示沒有從累加器里面讀取數(shù)據(jù),反之調(diào)用readRetainedSlice()方法從當(dāng)前累加器里面截取frameLength長度ByteBuf,返回從當(dāng)前readerIndex開始增加frameLength長度的Buffer子區(qū)域新保留切片。
FixedLengthFrameDecoder
/**
* A decoder that splits the received {@link ByteBuf}s by the fixed number
* of bytes. For example, if you received the following four fragmented packets:
* <pre>
* +---+----+------+----+
* | A | BC | DEFG | HI |
* +---+----+------+----+
* </pre>
* A {@link FixedLengthFrameDecoder}{@code (3)} will decode them into the
* following three packets with the fixed length:
* 如果固定長度為3,上面數(shù)據(jù)包會被解析成如下:
* <pre>
* +-----+-----+-----+
* | ABC | DEF | GHI |
* +-----+-----+-----+
* </pre>
*/
public class FixedLengthFrameDecoder extends ByteToMessageDecoder {
private final int frameLength;
public FixedLengthFrameDecoder(int frameLength) {
if (frameLength <= 0) {
throw new IllegalArgumentException(
"frameLength must be a positive integer: " + frameLength);
}
this.frameLength = frameLength;
}
@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);
}
}
protected Object decode(
@SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.readableBytes() < frameLength) {//當(dāng)前可讀字節(jié)小于固定長度,返回null,不添加到outList
return null;
} else {
return in.readRetainedSlice(frameLength);
}
}
}
三、行解碼器分析LineBasedFrameDecoder
基于行解碼器LineBasedFrameDecoder
- 成員變量
maxLength[行解碼器解析數(shù)據(jù)包最大長度],failFast[超越最大長度是否立即拋異常],
stripDelimiter[解析數(shù)據(jù)包是否帶換行符,換行符支持\n和\r],
discarding[解碼過程是否處于丟棄模式],
discardedBytes[解碼過程丟棄字節(jié)], - 調(diào)用decode()方法解析累加器cumulation數(shù)據(jù)把數(shù)據(jù)包添加到CodecOutputList,通過findEndOfLine()方法從累加器ByteBuf里面查找獲取行的結(jié)尾eol即\n或者\(yùn)r\n,
- 非丟棄模式查找到行的結(jié)尾eol計算從換行符到可讀字節(jié)的長度length和分隔符的長度判斷l(xiāng)ength是否大于解析數(shù)據(jù)包最大長度maxLength,大于maxLength則readerIndex指向行的結(jié)尾eol后面的可讀字節(jié)丟棄數(shù)據(jù)通過fail()方法傳播異常,判斷分隔符是否算在完整數(shù)據(jù)包范疇從buffer分割length長度獲取新保留切片并且buffer跳過分隔符readerIndex指向分隔符后面的可讀字節(jié),
- 未查找到行的結(jié)尾eol獲取可讀字節(jié)長度length超過解析數(shù)據(jù)包最大長度maxLength賦值discardedBytes為length讀指針readerIndex指向?qū)懼羔榳riterIndex賦值discarding為true進(jìn)入丟棄模式并且根據(jù)failFast調(diào)用fail()方法立即傳播fail異常,
- 丟棄模式查找到行的結(jié)尾eol按照丟棄字節(jié)+從換行符到可讀字節(jié)的長度計算length和換行符長度將readerIndex指向丟棄字節(jié)換行符后面的可讀字節(jié)賦值discardedBytes為0并且discarding為false表示當(dāng)前屬于非丟棄模式,根據(jù)failFast調(diào)用fail()方法立即傳播fail異常,
未查找到行的結(jié)尾eol則discardedBytes增加buffer的可讀字節(jié)并且讀指針readerIndex指向?qū)懼羔榳riterIndex
圖片.png
public class LineBasedFrameDecoder extends ByteToMessageDecoder {
/** 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;//解析的數(shù)據(jù)包時候帶換行符,false帶,true不帶
/** True if we're discarding input because we're already over maxLength. */
private boolean discarding;//超過最大長度時候拋棄
private int discardedBytes;//拋棄的字節(jié)數(shù)
/**
* Creates a new decoder.
* @param maxLength the maximum length of the decoded frame.
* A {@link TooLongFrameException} is thrown if
* the length of the frame exceeds this value.
*/
public LineBasedFrameDecoder(final int maxLength) {
this(maxLength, true, false);
}
/**
* Creates a new decoder.
* @param maxLength the maximum length of the decoded frame.
* A {@link TooLongFrameException} is thrown if
* the length of the frame exceeds this value.
* @param stripDelimiter whether the decoded frame should strip out the
* delimiter or not
* @param failFast If <tt>true</tt>, a {@link TooLongFrameException} is
* thrown as soon as the decoder notices the length of the
* frame will exceed <tt>maxFrameLength</tt> regardless of
* whether the entire frame has been read.
* If <tt>false</tt>, a {@link TooLongFrameException} is
* thrown after the entire frame that exceeds
* <tt>maxFrameLength</tt> has been read.
*/
public LineBasedFrameDecoder(final int maxLength, final boolean stripDelimiter, final boolean failFast) {
this.maxLength = maxLength;
this.failFast = failFast;
this.stripDelimiter = stripDelimiter;
}
@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);
}
}
/**
* Create a frame out of the {@link ByteBuf} and return it.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to
* @param buffer the {@link ByteBuf} from which to read data
* @return frame the {@link ByteBuf} which represent the frame or {@code null} if no frame could
* be created.
*/
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
final int eol = findEndOfLine(buffer);//尋找行的結(jié)尾,\n或者\(yùn)r\n
if (!discarding) {//非丟棄模式
if (eol >= 0) {
final ByteBuf frame;
final int length = eol - buffer.readerIndex();//endofline-readerIndex即為可讀字節(jié)
final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;//分隔符長度,2或者1
if (length > maxLength) {
buffer.readerIndex(eol + delimLength);//當(dāng)可讀字節(jié)大于行最大長度,則移動readerIndex到下一個可讀區(qū)域
fail(ctx, length);//傳播異常
return null;//返回null表示當(dāng)前什么也沒有解析
}
if (stripDelimiter) {//是否跳過分隔符
frame = buffer.readRetainedSlice(length);//解析數(shù)據(jù)不包含分隔符
buffer.skipBytes(delimLength);
} else {
frame = buffer.readRetainedSlice(length + delimLength);//解析數(shù)據(jù)包含分隔符
}
return frame;//返回解析數(shù)據(jù)包
} else {//readerIndex和writerIndex沒有換行符
final int length = buffer.readableBytes();
if (length > maxLength) {//可讀長度大于最大行長度
discardedBytes = length;//丟棄字節(jié)長度
buffer.readerIndex(buffer.writerIndex());//讀指針直接移到寫指針
discarding = true;//進(jìn)入丟棄模式
if (failFast) {//是否快速失敗,傳播異常
fail(ctx, "over " + discardedBytes);
}
}
return null;
}
} else {//丟棄模式
if (eol >= 0) {
final int length = discardedBytes + eol - buffer.readerIndex();//丟棄長度=discardedBytes +當(dāng)前可讀長度
final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
buffer.readerIndex(eol + delimLength);//移動指針到分隔符之后
discardedBytes = 0;//重置丟棄長度
discarding = false;//進(jìn)入非丟棄模式
if (!failFast) {
fail(ctx, length);
}
} else {//沒有找到分隔符,直接移動readerIndex到writerIndex
discardedBytes += buffer.readableBytes();
buffer.readerIndex(buffer.writerIndex());
}
return null;
}
}
private void fail(final ChannelHandlerContext ctx, int length) {
fail(ctx, String.valueOf(length));
}
四、分隔符解碼器DelimiterBasedFrameDecoder
圖片.png
public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
private final ByteBuf[] delimiters;
private final int maxFrameLength;
private final boolean stripDelimiter;
private final boolean failFast;
private boolean discardingTooLongFrame;
private int tooLongFrameLength;
/** Set only when decoding with "\n" and "\r\n" as the delimiter. */
private final LineBasedFrameDecoder lineBasedDecoder;
public DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf delimiter) {
this(maxFrameLength, true, delimiter);
}
public DelimiterBasedFrameDecoder(
int maxFrameLength, boolean stripDelimiter, ByteBuf delimiter) {
this(maxFrameLength, stripDelimiter, true, delimiter);
}
public DelimiterBasedFrameDecoder(
int maxFrameLength, boolean stripDelimiter, boolean failFast,
ByteBuf delimiter) {
this(maxFrameLength, stripDelimiter, failFast, new ByteBuf[] {
delimiter.slice(delimiter.readerIndex(), delimiter.readableBytes())});
}
public DelimiterBasedFrameDecoder(int maxFrameLength, ByteBuf... delimiters) {
this(maxFrameLength, true, delimiters);
}
public DelimiterBasedFrameDecoder(
int maxFrameLength, boolean stripDelimiter, ByteBuf... delimiters) {
this(maxFrameLength, stripDelimiter, true, delimiters);
}
//構(gòu)造方法
public DelimiterBasedFrameDecoder(
int maxFrameLength, boolean stripDelimiter, boolean failFast, ByteBuf... delimiters) {
validateMaxFrameLength(maxFrameLength);
if (delimiters == null) {
throw new NullPointerException("delimiters");
}
if (delimiters.length == 0) {
throw new IllegalArgumentException("empty delimiters");
}
if (isLineBased(delimiters) && !isSubclass()) {//初始化行解碼器
lineBasedDecoder = new LineBasedFrameDecoder(maxFrameLength, stripDelimiter, failFast);
this.delimiters = null;
} else {
this.delimiters = new ByteBuf[delimiters.length];
for (int i = 0; i < delimiters.length; i ++) {
ByteBuf d = delimiters[i];
validateDelimiter(d);
this.delimiters[i] = d.slice(d.readerIndex(), d.readableBytes());
}
lineBasedDecoder = null;
}
this.maxFrameLength = maxFrameLength;
this.stripDelimiter = stripDelimiter;
this.failFast = failFast;
}
/**判斷分隔符是否是 "\n" and "\r\n",是則為行解碼器 */
private static boolean isLineBased(final ByteBuf[] delimiters) {
if (delimiters.length != 2) {
return false;
}
ByteBuf a = delimiters[0];
ByteBuf b = delimiters[1];
if (a.capacity() < b.capacity()) {
a = delimiters[1];
b = delimiters[0];
}
return a.capacity() == 2 && b.capacity() == 1
&& a.getByte(0) == '\r' && a.getByte(1) == '\n'
&& b.getByte(0) == '\n';
}
@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);
}
}
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) {//是否丟棄模式
discardingTooLongFrame = false;//重置丟棄模式為false
buffer.skipBytes(minFrameLength + minDelimLength);//跳過
int tooLongFrameLength = this.tooLongFrameLength;
this.tooLongFrameLength = 0;
if (!failFast) {//是否已快速失敗
fail(tooLongFrameLength);
}
return null;
}
//最小分隔符分割的數(shù)據(jù)包仍大于最大數(shù)據(jù)包
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) {//非丟棄狀態(tài)
if (buffer.readableBytes() > maxFrameLength) {//可讀數(shù)據(jù)大于允許最大數(shù)據(jù)包
// Discard the content of the buffer until a delimiter is found.
tooLongFrameLength = buffer.readableBytes();
buffer.skipBytes(buffer.readableBytes());//直接跳過可讀數(shù)據(jù)
discardingTooLongFrame = true;//進(jìn)去丟棄狀態(tài)
if (failFast) {//是否快速失敗
fail(tooLongFrameLength);
}
}
} else {//丟棄狀態(tài)
// Still discarding the buffer since a delimiter is not found.
tooLongFrameLength += buffer.readableBytes();//記錄丟棄的字節(jié)數(shù)
buffer.skipBytes(buffer.readableBytes());//直接跳過可讀數(shù)據(jù)
}
return null;
}
}
private void fail(long frameLength) {
if (frameLength > 0) {
throw new TooLongFrameException(
"frame length exceeds " + maxFrameLength +
": " + frameLength + " - discarded");
} else {
throw new TooLongFrameException(
"frame length exceeds " + maxFrameLength +
" - discarding");
}
}
/**
* Returns the number of bytes between the readerIndex of the haystack and
* the first needle found in the haystack. -1 is returned if no needle is
* found in the haystack.
*/
private static int indexOf(ByteBuf haystack, ByteBuf needle) {
for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i ++) {
int haystackIndex = i;
int needleIndex;
for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex ++) {
if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) {
break;
} else {
haystackIndex ++;
if (haystackIndex == haystack.writerIndex() &&
needleIndex != needle.capacity() - 1) {
return -1;
}
}
}
if (needleIndex == needle.capacity()) {
// Found the needle from the haystack!
return i - haystack.readerIndex();
}
}
return -1;
}
private static void validateDelimiter(ByteBuf delimiter) {
if (delimiter == null) {
throw new NullPointerException("delimiter");
}
if (!delimiter.isReadable()) {
throw new IllegalArgumentException("empty delimiter");
}
}
private static void validateMaxFrameLength(int maxFrameLength) {
if (maxFrameLength <= 0) {
throw new IllegalArgumentException(
"maxFrameLength must be a positive integer: " +
maxFrameLength);
}
}
}
五、基于長度域解碼器LengthFieldBasedFrameDecoder
1、成員變量解析
- lengthFieldOffset:長度域偏移量即長度域在二進(jìn)制數(shù)據(jù)流里面偏移量
- lengthFieldLength:長度域長度即從長度域開始往后幾個字節(jié)組合起來表示長度
- lengthAdjustment:長度域表示長度+額外調(diào)整長度=數(shù)據(jù)包長度,即長度域計算完整數(shù)據(jù)包長度,長度額外調(diào)整
- initialBytesToStrip:decode出完整數(shù)據(jù)包之后向下傳播的時候是否需要砍掉幾個字節(jié)即解析數(shù)據(jù)包前面跳過字節(jié)
構(gòu)造函數(shù)
public LengthFieldBasedFrameDecoder(
ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,
int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
if (byteOrder == null) {
throw new NullPointerException("byteOrder");
}
if (maxFrameLength <= 0) {
throw new IllegalArgumentException(
"maxFrameLength must be a positive integer: " +
maxFrameLength);
}
if (lengthFieldOffset < 0) {
throw new IllegalArgumentException(
"lengthFieldOffset must be a non-negative integer: " +
lengthFieldOffset);
}
if (initialBytesToStrip < 0) {
throw new IllegalArgumentException(
"initialBytesToStrip must be a non-negative integer: " +
initialBytesToStrip);
}
if (lengthFieldOffset > maxFrameLength - lengthFieldLength) {
throw new IllegalArgumentException(
"maxFrameLength (" + maxFrameLength + ") " +
"must be equal to or greater than " +
"lengthFieldOffset (" + lengthFieldOffset + ") + " +
"lengthFieldLength (" + lengthFieldLength + ").");
}
this.byteOrder = byteOrder;
this.maxFrameLength = maxFrameLength;
this.lengthFieldOffset = lengthFieldOffset;
this.lengthFieldLength = lengthFieldLength;
this.lengthAdjustment = lengthAdjustment;
lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength;
this.initialBytesToStrip = initialBytesToStrip;
this.failFast = failFast;
}
示例1
* <b>lengthFieldOffset</b> = <b>0</b>
* <b>lengthFieldLength</b> = <b>2</b>
* lengthAdjustment = 0
* initialBytesToStrip = 0 (= do not strip header)
* BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
* +--------+----------------+ +--------+----------------+
* | Length | Actual Content |----->| Length | Actual Content |
* | 0x000C | "HELLO, WORLD" | | 0x000C | "HELLO, WORLD" |
* +--------+----------------+ +--------+----------------+
new LengthFieldBasedFrameDecoder(Integer.MAX, 0, 2);
1.第一個參數(shù)是 maxFrameLength 表示的是包的最大長度,超出包的最大長度netty將會做一些特殊處理,后面會講到
2.第二個參數(shù)指的是長度域的偏移量lengthFieldOffset,在這里是0,表示無偏移
3.第三個參數(shù)指的是長度域長度lengthFieldLength,這里是2,表示長度域的長度為2
示例2
* lengthFieldOffset = 0
* lengthFieldLength = 2
* lengthAdjustment = 0
* <b>initialBytesToStrip</b> = <b>2</b> (= the length of the Length field)
* BEFORE DECODE (14 bytes) AFTER DECODE (12 bytes)
* +--------+----------------+ +----------------+
* | Length | Actual Content |----->| Actual Content |
* | 0x000C | "HELLO, WORLD" | | "HELLO, WORLD" |
* +--------+----------------+ +----------------+
new LengthFieldBasedFrameDecoder(Integer.MAX, 0, 2, 0, 2);
前面三個參數(shù)的含義和上文相同
第四個參數(shù)lengthAdjustment,后面再講
第五個參數(shù)就是initialBytesToStrip,這里為2,表示獲取完一個完整的數(shù)據(jù)包之后,忽略前面的2個字節(jié)(長度)
示例3
* lengthFieldOffset = 0
* lengthFieldLength = 2
* <b>lengthAdjustment</b> = <b>-2</b> (= the length of the Length field)
* initialBytesToStrip = 0
*
* BEFORE DECODE (14 bytes) AFTER DECODE (14 bytes)
* +--------+----------------+ +--------+----------------+
* | Length | Actual Content |----->| Length | Actual Content |
* | 0x000E | "HELLO, WORLD" | | 0x000E | "HELLO, WORLD" |
* +--------+----------------+ +--------+----------------+
new LengthFieldBasedFrameDecoder(Integer.MAX, 0, 2,-2,0);
lengthFieldLength 是2,lengthAdjustment為-2,表示數(shù)據(jù)包長度0x000E-2,即為0x000C
示例4
* <b>lengthFieldOffset</b> = <b>2</b> (= the length of Header 1)
* <b>lengthFieldLength</b> = <b>3</b>
* lengthAdjustment = 0
* initialBytesToStrip = 0
*
* BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes)
* +----------+----------+----------------+ +----------+----------+----------------+
* | Header 1 | Length | Actual Content |----->| Header 1 | Length | Actual Content |
* | 0xCAFE | 0x00000C | "HELLO, WORLD" | | 0xCAFE | 0x00000C | "HELLO, WORLD" |
* +----------+----------+----------------+ +----------+----------+----------------+
new LengthFieldBasedFrameDecoder(Integer.MAX, 2, 3, 0, 0);
長度域偏移為2,長度域大小為3,即0x00000C
示例5
* lengthFieldOffset = 0
* lengthFieldLength = 3
* <b>lengthAdjustment</b> = <b>2</b> (= the length of Header 1)
* initialBytesToStrip = 0
*
* BEFORE DECODE (17 bytes) AFTER DECODE (17 bytes)
* +----------+----------+----------------+ +----------+----------+----------------+
* | Length | Header 1 | Actual Content |----->| Length | Header 1 | Actual Content |
* | 0x00000C | 0xCAFE | "HELLO, WORLD" | | 0x00000C | 0xCAFE | "HELLO, WORLD" |
* +----------+----------+----------------+ +----------+----------+----------------+
new LengthFieldBasedFrameDecoder(Integer.MAX, 0, 3, 2, 0);
長度域中0x00000C ,Header 占用2字節(jié),所以數(shù)據(jù)包長度為0x00000C +2(lengthAdjustment)
示例6
* lengthFieldOffset = 1 (= the length of HDR1)
* lengthFieldLength = 2
* <b>lengthAdjustment</b> = <b>1</b> (= the length of HDR2)
* <b>initialBytesToStrip</b> = <b>3</b> (= the length of HDR1 + LEN)
*
* BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes)
* +------+--------+------+----------------+ +------+----------------+
* | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
* | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" |
* +------+--------+------+----------------+ +------+----------------+
new LengthFieldBasedFrameDecoder(Integer.MAX, 1, 2, 1, 3);
數(shù)據(jù)包長度為0x000C +1(lengthAdjustment),截取前面3(initialBytesToStrip)個字節(jié)
示例7
* lengthFieldOffset = 1
* lengthFieldLength = 2
* <b>lengthAdjustment</b> = <b>-3</b> (= the length of HDR1 + LEN, negative)
* <b>initialBytesToStrip</b> = <b> 3</b>
*
* BEFORE DECODE (16 bytes) AFTER DECODE (13 bytes)
* +------+--------+------+----------------+ +------+----------------+
* | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
* | 0xCA | 0x0010 | 0xFE | "HELLO, WORLD" | | 0xFE | "HELLO, WORLD" |
* +------+--------+------+----------------+ +------+----------------+
2、decode方法分析
- 計算需要抽取的數(shù)據(jù)包長度。
- 跳過字節(jié)邏輯處理。
- 丟棄模式下的處理。
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (discardingTooLongFrame) {//先判斷是否丟棄模式,進(jìn)行丟棄處理
long bytesToDiscard = this.bytesToDiscard;//待丟棄的字節(jié)數(shù)
int localBytesToDiscard = (int) Math.min(bytesToDiscard, in.readableBytes());//
in.skipBytes(localBytesToDiscard);
bytesToDiscard -= localBytesToDiscard;//待丟棄的字節(jié)數(shù)減去本次已丟棄,即下次需丟棄的字節(jié)數(shù)
this.bytesToDiscard = bytesToDiscard;
failIfNecessary(false);
}
//如果當(dāng)前可讀字節(jié)數(shù)還未到達(dá)長度域結(jié)尾,則不足以解析數(shù)據(jù)包
if (in.readableBytes() < lengthFieldEndOffset) {
return null;
}
int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset;//長度域絕對位置
long frameLength = getUnadjustedFrameLength(in, actualLengthFieldOffset, lengthFieldLength, byteOrder);//抽取的數(shù)據(jù)包長度
if (frameLength < 0) {
in.skipBytes(lengthFieldEndOffset);
throw new CorruptedFrameException(
"negative pre-adjustment length field: " + frameLength);
}
frameLength += lengthAdjustment + lengthFieldEndOffset;//實(shí)際抽取的數(shù)據(jù)包長度
if (frameLength < lengthFieldEndOffset) {
in.skipBytes(lengthFieldEndOffset);
throw new CorruptedFrameException(
"Adjusted frame length (" + frameLength + ") is less " +
"than lengthFieldEndOffset: " + lengthFieldEndOffset);
}
if (frameLength > maxFrameLength) {//數(shù)據(jù)包長度大于maxFrameLength,進(jìn)去丟棄模式
long discard = frameLength - in.readableBytes();
tooLongFrameLength = frameLength;
if (discard < 0) {
// buffer contains more bytes then the frameLength so we can discard all now
in.skipBytes((int) frameLength);//直接丟棄frameLength長度的數(shù)據(jù)包
} else {
// Enter the discard mode and discard everything received so far.
discardingTooLongFrame = true;//丟棄模式
bytesToDiscard = discard;//還需要丟棄字節(jié)數(shù)
in.skipBytes(in.readableBytes());
}
failIfNecessary(true);//
return null;
}
// never overflows because it's less than maxFrameLength
int frameLengthInt = (int) frameLength;
if (in.readableBytes() < frameLengthInt) {//可讀數(shù)據(jù)小于實(shí)際抽取的數(shù)據(jù)包長度,即不完整數(shù)據(jù)包
return null;
}
if (initialBytesToStrip > frameLengthInt) {
in.skipBytes(frameLengthInt);
throw new CorruptedFrameException(
"Adjusted frame length (" + frameLength + ") is less " +
"than initialBytesToStrip: " + initialBytesToStrip);
}
in.skipBytes(initialBytesToStrip);//跳過字節(jié)數(shù)
// extract frame
int readerIndex = in.readerIndex();//讀指針
int actualFrameLength = frameLengthInt - initialBytesToStrip;//實(shí)際數(shù)據(jù)包
ByteBuf frame = extractFrame(ctx, in, readerIndex, actualFrameLength);
in.readerIndex(readerIndex + actualFrameLength);
return frame;
}
//支持1、2、3、4、8的length
protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
buf = buf.order(order);
long frameLength;
switch (length) {
case 1:
frameLength = buf.getUnsignedByte(offset);
break;
case 2:
frameLength = buf.getUnsignedShort(offset);
break;
case 3:
frameLength = buf.getUnsignedMedium(offset);
break;
case 4:
frameLength = buf.getUnsignedInt(offset);
break;
case 8:
frameLength = buf.getLong(offset);
break;
default:
throw new DecoderException(
"unsupported lengthFieldLength: " + lengthFieldLength + " (expected: 1, 2, 3, 4, or 8)");
}
return frameLength;
}
protected ByteBuf extractFrame(ChannelHandlerContext ctx, ByteBuf buffer, int index, int length) {
return buffer.retainedSlice(index, length);
}