本文使用golang 实现一个基于长度字段的解码器 LengthFieldBasedFrameDecoder
LengthFieldBasedFrameDecoder
type LengthFieldBasedFrameDecoder struct {
byteOrder binary.ByteOrder
maxFrameLength int
lengthFieldOffset int
lengthFieldLength int
lengthAdjustment int
initialBytesToStrip int
}
Decode 方法
func (l *LengthFieldBasedFrameDecoder) Decode(reader *bufio.Reader) (io.Reader, error) {
// lengthFieldEndOffset
lengthFieldEndOffset := l.lengthFieldOffset + l.lengthFieldLength
// read header buffer
headerBuffer := make([]byte, lengthFieldEndOffset)
//reader head from reader
n, err := io.ReadFull(reader, headerBuffer)
if n != len(headerBuffer) || err != nil {
panic(fmt.Errorf("reade message lengthFieldEndOffset faield %v", err))
}
//lengthFiledBuff
lengthFieldBuff := headerBuffer[l.lengthFieldOffset:lengthFieldEndOffset]
//frame length
frameLength := unpackFieldLength(l.byteOrder, l.lengthFieldLength, lengthFieldBuff)
//adjust
frameLength += int64(l.lengthAdjustment + lengthFieldEndOffset)
//frameReader
frameReader := io.MultiReader(
// lengthFieldOffset + lengthFieldLength
bytes.NewReader(headerBuffer),
// frameLength - len(headerBuffer)
io.LimitReader(reader, frameLength-int64(lengthFieldEndOffset)),
)
// strip bytes
if l.initialBytesToStrip > 0 {
n, err := io.CopyN(io.Discard, frameReader, int64(l.initialBytesToStrip))
if n != int64(l.initialBytesToStrip) || err != nil {
panic(fmt.Errorf("initialBytesToStrip: %d -> %d, %w", l.initialBytesToStrip, n, err))
}
}
//转成 io.Reader
return frameReader, nil
}
unpackFieldLength 解析长度字段
func unpackFieldLength(byteOrder binary.ByteOrder, fieldLen int, buff []byte) (frameLength int64) {
switch fieldLen {
case 1:
frameLength = int64(buff[0])
case 2:
frameLength = int64(byteOrder.Uint16(buff))
case 4:
frameLength = int64(byteOrder.Uint32(buff))
case 8:
frameLength = int64(byteOrder.Uint64(buff))
default:
panic(fmt.Errorf("should not reach here"))
}
return
}
说明
主要参考netty的 LengthFieldBasedFrameDecoder实现