|
| 1 | +// TLV,即Tag(Type)—Length—Value,是一种简单实用的数据传输方案。 |
| 2 | +//在TLV的定义中,可以知道它包括三个域,分别为:标签域(Tag),长度域(Length),内容域(Value)。这里的长度域的值实际上就是内容域的长度。 |
| 3 | +// |
| 4 | +//解码前 (20 bytes) 解码后 (20 bytes) |
| 5 | +//+------------+------------+-----------------+ +------------+------------+-----------------+ |
| 6 | +//| Tag | Length | Value |----->| Tag | Length | Value | |
| 7 | +//| 0x00000001 | 0x0000000C | "HELLO, WORLD" | | 0x00000001 | 0x0000000C | "HELLO, WORLD" | |
| 8 | +//+------------+------------+-----------------+ +------------+------------+-----------------+ |
| 9 | +// Tag: uint32类型,占4字节,Tag作为MsgId,暂定为1 |
| 10 | +// Length:uint32类型,占4字节,Length标记Value长度12(hex:0x0000000C) |
| 11 | +// Value: 共12个字符,占12字节 |
| 12 | +// |
| 13 | +// 说明: |
| 14 | +// lengthFieldOffset = 4 (Length的字节位索引下标是4) 长度字段的偏差 |
| 15 | +// lengthFieldLength = 4 (Length是4个byte) 长度字段占的字节数 |
| 16 | +// lengthAdjustment = 0 (Length只表示Value长度,程序只会读取Length个字节就结束,后面没有来,故为0,若Value后面还有crc占2字节的话,那么此处就是2。若Length标记的是Tag+Length+Value总长度,那么此处是-8) |
| 17 | +// initialBytesToStrip = 0 (这个0表示返回完整的协议内容Tag+Length+Value,如果只想返回Value内容,去掉Tag的4字节和Length的4字节,此处就是8) 从解码帧中第一次去除的字节数 |
| 18 | +// maxFrameLength = 2^32 + 4 + 4 (Length为uint类型,故2^32次方表示Value最大长度,此外Tag和Length各占4字节) |
| 19 | + |
| 20 | +package examples |
| 21 | + |
| 22 | +import ( |
| 23 | + "bytes" |
| 24 | + "encoding/binary" |
| 25 | + "encoding/hex" |
| 26 | + "github.com/aceld/zinx/ziface" |
| 27 | + "github.com/aceld/zinx/zlog" |
| 28 | + "math" |
| 29 | + "unsafe" |
| 30 | +) |
| 31 | + |
| 32 | +const TLV_HEADER_SIZE = 8 //表示TLV空包长度 |
| 33 | + |
| 34 | +type LtvData struct { |
| 35 | + Tag uint32 |
| 36 | + Length uint32 |
| 37 | + Value string |
| 38 | +} |
| 39 | + |
| 40 | +type LTVDecoder struct { |
| 41 | +} |
| 42 | + |
| 43 | +func (this *LTVDecoder) GetLengthField() ziface.LengthField { |
| 44 | + // +---------------+---------------+---------------+ |
| 45 | + // | Length | Tag | Value | |
| 46 | + // | uint32(4byte) | uint32(4byte) | n byte | |
| 47 | + // +---------------+---------------+---------------+ |
| 48 | + // Length:uint32类型,占4字节,Length标记Value长度 |
| 49 | + // Tag: uint32类型,占4字节 |
| 50 | + // Value: 占n字节 |
| 51 | + // |
| 52 | + //说明: |
| 53 | + // lengthFieldOffset = 0 (Length的字节位索引下标是0) 长度字段的偏差 |
| 54 | + // lengthFieldLength = 4 (Length是4个byte) 长度字段占的字节数 |
| 55 | + // lengthAdjustment = 4 (Length只表示Value长度,程序只会读取Length个字节就结束,后面没有来,故为0,若Value后面还有crc占2字节的话,那么此处就是2。若Length标记的是Tag+Length+Value总长度,那么此处是-8) |
| 56 | + // initialBytesToStrip = 0 (这个0表示返回完整的协议内容Tag+Length+Value,如果只想返回Value内容,去掉Tag的4字节和Length的4字节,此处就是8) 从解码帧中第一次去除的字节数 |
| 57 | + // maxFrameLength = 2^32 + 4 + 4 (Length为uint32类型,故2^32次方表示Value最大长度,此外Tag和Length各占4字节) |
| 58 | + //默认使用TLV封包方式 |
| 59 | + return ziface.LengthField{ |
| 60 | + MaxFrameLength: math.MaxUint32 + 4 + 4, |
| 61 | + LengthFieldOffset: 0, |
| 62 | + LengthFieldLength: 4, |
| 63 | + LengthAdjustment: 4, |
| 64 | + InitialBytesToStrip: 0, |
| 65 | + Order: binary.LittleEndian, //好吧,我看了代码,使用的是小端😂 |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +func (this *LTVDecoder) Intercept(chain ziface.Chain) ziface.Response { |
| 70 | + request := chain.Request() |
| 71 | + if request != nil { |
| 72 | + switch request.(type) { |
| 73 | + case ziface.IRequest: |
| 74 | + iRequest := request.(ziface.IRequest) |
| 75 | + iMessage := iRequest.GetMessage() |
| 76 | + if iMessage != nil { |
| 77 | + data := iMessage.GetData() |
| 78 | + zlog.Ins().DebugF("TLV-RawData size:%d data:%s\n", len(data), hex.EncodeToString(data)) |
| 79 | + datasize := len(data) |
| 80 | + _data := LtvData{} |
| 81 | + if datasize >= TLV_HEADER_SIZE { |
| 82 | + _data.Length = binary.LittleEndian.Uint32(data[0:4]) |
| 83 | + _data.Tag = binary.LittleEndian.Uint32(data[4:8]) |
| 84 | + value := make([]byte, _data.Length) |
| 85 | + binary.Read(bytes.NewBuffer(data[8:8+_data.Length]), binary.LittleEndian, value) |
| 86 | + _data.Value = string(value) |
| 87 | + iMessage.SetMsgID(_data.Tag) |
| 88 | + iRequest.SetResponse(_data) |
| 89 | + zlog.Ins().DebugF("TLV-DecodeData size:%d data:%+v\n", unsafe.Sizeof(data), _data) |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + } |
| 94 | + return chain.Proceed(chain.Request()) |
| 95 | +} |
0 commit comments