1.LineBasedFrameDecoder 1.先找到結束符索引 private static int findEndOfLine(final ByteBuf buffer) { final int n = buffer.writerIndex(); for (int i = buffer.readerIndex(); i < n; i ++) { final byte b = buffer.getByte(i); if (b == '\n') { return i; } else if (b == '\r' && i < n - 1 && buffer.getByte(i + 1) == '\n') { return i; // \r\n } } return -1; // Not found. } 2.而後讀取數據bytes 轉換成對象返回,容錯處理暫時不分析 核心代碼 if (eol >= 0) { final ByteBuf frame; final int length = eol - buffer.readerIndex(); final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1; if (length > maxLength) { buffer.readerIndex(eol + delimLength); fail(ctx, length); return null; } if (stripDelimiter) {//是否連結束符返回 true 不返回 frame = buffer.readBytes(length); buffer.skipBytes(delimLength);//跳過結束符數據 } else { frame = buffer.readBytes(length + delimLength); } return frame; } 2.StringDecoder 分析 比較簡單,ByteBuf 轉換 string @Override protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { out.add(msg.toString(charset)); } 3.DelimiterBasedFrameDecoder 自定義結束符解碼分析,原理基本跟 LineBasedFrameDecoder 相同 1.找到結束符 ByteBuf 對象,可支持多個 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; } } 2.而後讀取數據bytes 轉換成對象返回,容錯處理暫時不分析 核心代碼 if (stripDelimiter) {//是否連結束符返回 true 不返回 frame = buffer.readBytes(minFrameLength); buffer.skipBytes(minDelimLength);//跳過結束符數據 } else { frame = buffer.readBytes(minFrameLength + minDelimLength); } return frame; 4.FixedLengthFrameDecoder 比較簡單 protected Object decode(@SuppressWarnings("UnusedParameters") ChannelHandlerContext ctx, ByteBuf in) throws Exception { if (in.readableBytes() < frameLength) { return null; } else { return in.readBytes(frameLength); } } 5.LengthFieldBasedFrameDecoder 在 FixedLengthFrameDecoder 基礎上指定偏移讀取長度,動態幀長度 1.先看構造方法 /** * Creates a new instance. * * @param byteOrder * the {@link ByteOrder} of the length field * @param maxFrameLength * the maximum length of the frame. If the length of the frame is * greater than this value, {@link TooLongFrameException} will be * thrown. * @param lengthFieldOffset * the offset of the length field * @param lengthFieldLength * the length of the length field * @param lengthAdjustment * the compensation value to add to the value of the length field * @param initialBytesToStrip * the number of first bytes to strip out from the decoded frame * @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 LengthFieldBasedFrameDecoder( ByteOrder byteOrder, //傳輸方式,默認ByteOrder.BIG_ENDIAN int maxFrameLength, //幀最大長度 int lengthFieldOffset,//數據長度偏移,忽略包頭信息 int lengthFieldLength,//數據長度大小 int lengthAdjustment, //附加數據長度 默認0 int initialBytesToStrip, boolean failFast //true 超過 maxFrameLength 長度會拋異常,看處理寫得不清晰 ) { this.byteOrder = byteOrder; this.maxFrameLength = maxFrameLength; this.lengthFieldOffset = lengthFieldOffset; this.lengthFieldLength = lengthFieldLength; this.lengthAdjustment = lengthAdjustment; lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength; this.initialBytesToStrip = initialBytesToStrip; this.failFast = failFast; } 2.核心分析 protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { if (discardingTooLongFrame) { //是否丟棄處理 long bytesToDiscard = this.bytesToDiscard; int localBytesToDiscard = (int) Math.min(bytesToDiscard, in.readableBytes()); in.skipBytes(localBytesToDiscard);//跳過丟棄數據 bytesToDiscard -= localBytesToDiscard; this.bytesToDiscard = bytesToDiscard;//記錄索引 failIfNecessary(false); } //少於頭信息忽略 if (in.readableBytes() < lengthFieldEndOffset) { return null; } //計算實際數據讀取索引 int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset; //獲取數據長度 long frameLength = getFrameLength(in, actualLengthFieldOffset); if (frameLength < 0) { in.skipBytes(lengthFieldEndOffset); throw new CorruptedFrameException( "negative pre-adjustment length field: " + frameLength); } // 幀總長度 = 數據長度+附加數據長度+ 偏移總長度 frameLength += lengthAdjustment + lengthFieldEndOffset; if (frameLength < lengthFieldEndOffset) { in.skipBytes(lengthFieldEndOffset); throw new CorruptedFrameException( "Adjusted frame length (" + frameLength + ") is less " + "than lengthFieldEndOffset: " + lengthFieldEndOffset); } if (frameLength > maxFrameLength) { 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); } else { // Enter the discard mode and discard everything received so far. discardingTooLongFrame = true; bytesToDiscard = discard; in.skipBytes(in.readableBytes()); } failIfNecessary(true); return null; } // never overflows because it's less than maxFrameLength int frameLengthInt = (int) frameLength; if (in.readableBytes() < frameLengthInt) { return null; } if (initialBytesToStrip > frameLengthInt) { in.skipBytes(frameLengthInt); throw new CorruptedFrameException( "Adjusted frame length (" + frameLength + ") is less " + "than initialBytesToStrip: " + initialBytesToStrip); } in.skipBytes(initialBytesToStrip); // extract frame int readerIndex = in.readerIndex();//當前讀索引 int actualFrameLength = frameLengthInt - initialBytesToStrip;//不清楚爲何-initialBytesToStrip ByteBuf frame = extractFrame(ctx, in, readerIndex, actualFrameLength); //拷貝數據 in.readerIndex(readerIndex + actualFrameLength);//修改讀索引 return frame; } private long getFrameLength(ByteBuf in, int actualLengthFieldOffset) { in = in.order(byteOrder); long frameLength; switch (lengthFieldLength) { case 1: frameLength = in.getUnsignedByte(actualLengthFieldOffset); break; case 2: frameLength = in.getUnsignedShort(actualLengthFieldOffset); break; case 3: frameLength = in.getUnsignedMedium(actualLengthFieldOffset); break; case 4: frameLength = in.getUnsignedInt(actualLengthFieldOffset); break; case 8: frameLength = in.getLong(actualLengthFieldOffset); break; default: throw new Error("should not reach here"); } return frameLength; }