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 == ' ') { return i; } else if (b == ' ' && i < n - 1 && buffer.getByte(i + 1) == ' ') { return i; // } } return -1; // Not found. } 2.然后读取数据bytes 转换成对象返回,容错处理暂时不分析 核心代码 if (eol >= 0) { final ByteBuf frame; final int length = eol - buffer.readerIndex(); final int delimLength = buffer.getByte(eol) == ' '? 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; }