重要参数
maxFrameLength 报文最大长度,超出则直接丢弃
lengthFieldOffset 长度字段的偏移量,即报文长度字段的下标
lengthFieldLength 报文长度字段的字节长度
lengthAdjustment 长度字段的调整字段
initialBytesToStrip 报文需要跳过的字节数(从头开始)
其他:
lengthFeildEndOffset 报文长度字段结束的字节下标
参数间的关系
令 frameLength 为lengthField字段的值
lengthAdjustment + frameLength 为lengthField字段后到frame结尾的长度
initialBytesToStrip + lengthAdjustment + frameLength + lengthFeildEndOffset 为实际要读取的长度
解码方法 decode
decode方法的作用是根据所填入的参数,将应该读取到的完成frame从输入流ByteBuf中提取出来并返回,在读取的过程中利用五大参数对所要读取的字节流进行了一些基本的校验:
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);
}
//报文实际长度
frameLength += lengthAdjustment + lengthFieldEndOffset;
if (frameLength < lengthFieldEndOffset) {
failOnFrameLengthLessThanLengthFieldEndOffset(in, frameLength, lengthFieldEndOffset);
}
if (frameLength > maxFrameLength) { //一旦超出了,那么本次frame肯定会被丢
exceededFrameLength(in, frameLength);
return null;
}
// never overflows because it's less than maxFrameLength
int frameLengthInt = (int) frameLength;
if (in.readableBytes() < frameLengthInt) { //可读字节数不足
return null;
}
if (initialBytesToStrip > frameLengthInt) { //要跳过的字节数大于报文长度,无法读取
failOnFrameLengthLessThanInitialBytesToStrip(in, frameLength, initialBytesToStrip);
}
in.skipBytes(initialBytesToStrip); //跳过initialBytesToStrip个字节
// extract frame
int readerIndex = in.readerIndex(); //获取当前读下标
int actualFrameLength = frameLengthInt - initialBytesToStrip; // 最终报文长度
ByteBuf frame = extractFrame(ctx, in, readerIndex, actualFrameLength);//提取报文
in.readerIndex(readerIndex + actualFrameLength); //重置读下标
return frame;
}
对于过长报文的处理
只要frame的长度(也就是报文长度字段的值)超出了最大长度限制参数 maxFrameLength ,就会将frame丢弃,还有可能对下次的bytebuf读取有影响(没丢够字节数继续丢):
private void exceededFrameLength(ByteBuf in, long frameLength) {
long discard = frameLength - in.readableBytes(); //计算本frame要丢弃的字节数
tooLongFrameLength = frameLength;
if (discard < 0) { // 如果丢弃了这次的frame,输入流中还有字节可以读
in.skipBytes((int) frameLength); //那么就直接先把本次的frame都丢弃
} else {
discardingTooLongFrame = true;//开启继续丢弃模式,因为这轮的字节还没丢够需要继续丢
bytesToDiscard = discard;
in.skipBytes(in.readableBytes());
}
failIfNecessary(true);
}
private void discardingTooLongFrame(ByteBuf in) {
long bytesToDiscard = this.bytesToDiscard;
int localBytesToDiscard = (int) Math.min(bytesToDiscard, in.readableBytes());
in.skipBytes(localBytesToDiscard);//如果还有需要丢弃的字节,继续丢弃(可能是上轮造成的)
bytesToDiscard -= localBytesToDiscard;
this.bytesToDiscard = bytesToDiscard;
failIfNecessary(false);
}