金融系统中PBOC/EMV的TLV的算法实现(含C++/C#)

来源:互联网 发布:mac win10 iso 下载 编辑:程序博客网 时间:2024/04/28 08:20

http://www.cnblogs.com/liping13599168/archive/2011/06/15/2081366.html  

TLV即Tag-Length-Value,常在IC卡与POS终端设备中通过这样的一个应用通信协议进行数据交换。在金融系统以及认证中,PBOC以及EMV的认证规范文档上面也有对TLV做了一些说明,由于认证规范都是英文文档,所以有些人可能不易于理解。首先我先介绍下什么是TLV,TLV的用途是什么,以及如何实现它的打包解包算法。

 

      金融系统中的TLV是BER-TLV编码的一个特例编码规范,而BER-TLV是ISO定义中的规范。在TLV的定义中,可以知道它包括三个域,分别为:标签域(Tag),长度域(Length),内容域(Value)。这里的长度域的值实际上就是内容域的长度

      其实,在BER编码的方式有两种情况,一种是确定长度的方式,一种是不确定长度的方式,而金融TLV选择了确定长度的方式,这样在设备之间的数据传输量上就可以减少。

 

Tag域说明:

      先来看下TLV的Tag是如何编码的,先看下图:

image

 

这张图说明了Tag域第一个字节的编码格式。其中b8-b1代表1个字节中的8个位。

其中b8,b7代表数据的类别。根据2个位的组合,有四种类别:通用类别,应用类别,上下文语境类别,专用类别。这个主要用于在于终端设备交互的时候,确定数据处理的类型。

b6代表的是数据元结构,也就是说它是属于简单数据元结构,还是属于结构(复合)数据元结构。当b6为1的时候,就需要后续的字节进行扩展。也就是说复合的TLV中,value域里也包含一个或多个TLV,这个稍后接着介绍。

当b5-b1代表串行号,当5个位都为1时,需要将tag域扩展到下一个字节中,也就是Tag占2个字节;而当5个位都不全为1时,该Tag域就只占1个字节。

      现在,看下b5-b1:11111的情况:

image

      从图中我们看到BER-TLV编码中,当b8为1时,Tag还需要有后续字节,直到b8为0为止。从EMV文档中的说明,Tag最多只占用2个字节,所以这样就相对比较简单一些了。当b8为0时,该Tag域结束,总共就占用2个字节。

 

Length域说明:

      在文档中没有图片叙述,我自绘一个:

image

当b8为0时,该字节的b7-b1作为value域的长度;当b8为1时,b7-b1作为后续字节的长度,也就是说,例如有这样一个值:10000011,代表后续还有3个字节作为value域的长度(本字节不算,本字节变为作为一个Length的索引)。3个字节代表value的长度,意味着什么呢,意味着内容的长度当需要很大的时候,字节的位数就会跟着越高,3个字节就代表最大可以有256*256*256的长度。

 

Value域说明:

      也是分成两种情况考虑,就是前面说到的Tag分成两个数据元结构,一种是简单数据元结构,一种是复合数据元架构:

      先来看看简单数据元结构:

     image

Tag就是Tag,没有子标签Tag,基本结构就是T-L-V。

      再看下符合数据元结构:

image

后面的Value说明:Primitive or constructed BER-TLV data object number,包含一个简单数据元结构或者也可以是一个符合数据元结构。这样可以看出,算法中必须要实现Tag的嵌套功能,递归算法不可少。

 

算法实现:

      根据以上的说明现在来实现它的打包解包的算法(打包的目的是将一个从终端上发的请求数据——字节数组,构造成一系列的TLV结构实体;解包的目的刚好相反,就是将TLV结构实体解析成字节数组,然后通过IC卡发送到终端上)。

      首先定义一个TLV结构实体:

?
1
2
3
4
5
6
7
8
9
// TLV结构体
struct TLVEntity {
    unsignedchar* Tag;         //标记
    unsignedchar* Length;      //数据长度
    unsignedchar* Value;       //数据
    unsignedint TagSize;      //标记占用字节数
    unsignedint LengthSize;   //数据长度占用字节数
    TLVEntity* Sub_TLVEntity;   //子嵌套TLV实体
};
其中TagSize代表Tag字段的字节长度,LengthSize代表Length的字节长度,这里的Length记住要使用char*,由于前面说过,Length可能包含多个字节,通过多个字节确定Value域的长度,Sub_TLVEntity作为子嵌套的TLV结构体。

      定义一个TLVPackage的打包类:

TLVPackage.h:

?
1
2
3
4
5
6
7
8
9
10
11
// TLV打包类
class TLVPackage
{
public:
    TLVPackage();
    virtual ~TLVPackage();
    //构造TLV实体
    static void Construct(unsignedchar* buffer, unsigned int bufferLength, TLVEntity* tlvEntity, unsigned int& entityLength, unsigned int status=0);
    //解析TLV字节数组
    static void Parse(TLVEntity* tlvEntity, unsigned int entityLength, unsigned char* buffer, unsigned int& bufferLength);
};

具体方法实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// 构造TLV
void TLVPackage:: Construct(
    unsignedchar* buffer,
    unsignedint bufferLength,
    TLVEntity* tlvEntity,
    unsignedint& entityLength,
    unsignedint status
    )
{
    int currentTLVIndex = 0;
    int currentIndex = 0;
    int currentStatus = 'T';//状态字符
    unsignedlong valueSize = 0;
 
    while(currentIndex < bufferLength)
    {
        switch(currentStatus)
        {
        case 'T':
            valueSize = 0;
            //判断是否单一结构
            if((status == 1 && buffer[currentIndex] & 0x20) != 0x20)
            {
                tlvEntity[currentTLVIndex].Sub_TLVEntity = NULL; //单一结构时将子Tag置空
                //判断是否多字节Tag
                if((buffer[currentIndex] & 0x1f) == 0x1f)
                {
                    int endTagIndex = currentIndex;
                    while((buffer[++endTagIndex] & 0x80) == 0x80); //判断第二个字节的最高位是否为1
                    int tagSize = endTagIndex - currentIndex + 1; //计算Tag包含多少字节
 
                    tlvEntity[currentTLVIndex].Tag = new unsignedchar[tagSize];
                    memcpy(tlvEntity[currentTLVIndex].Tag, buffer + currentIndex, tagSize);
                    tlvEntity[currentTLVIndex].Tag[tagSize] = 0;
 
                    tlvEntity[currentTLVIndex].TagSize = tagSize;
 
                    currentIndex += tagSize;
                }
                else
                {
                    tlvEntity[currentTLVIndex].Tag = new unsignedchar[1];
                    memcpy(tlvEntity[currentTLVIndex].Tag, buffer + currentIndex, 1);
                    tlvEntity[currentTLVIndex].Tag[1] = 0;
 
                    tlvEntity[currentTLVIndex].TagSize = 1;
 
                    currentIndex += 1;
                }
            }
            else
            {
                //判断是否多字节Tag
                if((buffer[currentIndex] & 0x1f) == 0x1f)
                {
                    int endTagIndex = currentIndex;
                    while((buffer[++endTagIndex] & 0x80) == 0x80); //判断第二个字节的最高位是否为1
                    int tagSize = endTagIndex - currentIndex + 1; //计算Tag包含多少字节
 
                    tlvEntity[currentTLVIndex].Tag = new unsignedchar[tagSize];
                    memcpy(tlvEntity[currentTLVIndex].Tag, buffer + currentIndex, tagSize);
                    tlvEntity[currentTLVIndex].Tag[tagSize] = 0;
 
                    tlvEntity[currentTLVIndex].TagSize = tagSize;
 
                    currentIndex += tagSize;
                }
                else
                {
                    tlvEntity[currentTLVIndex].Tag = new unsignedchar[1];
                    memcpy(tlvEntity[currentTLVIndex].Tag, buffer + currentIndex, 1);
                    tlvEntity[currentTLVIndex].Tag[1] = 0;
 
                    tlvEntity[currentTLVIndex].TagSize = 1;
 
                    currentIndex += 1;             
                }
 
                //分析SubTag
                int subLength = 0; 
                 
                unsignedchar* temp;
                if((buffer[currentIndex] & 0x80) == 0x80)
                {
                    for (int index = 0; index < 2; index++)
                    {
                        subLength += buffer[currentIndex + 1 + index] << (index * 8); //计算Length域的长度
                    }
 
                    temp = new unsignedchar[subLength];
 
                    memcpy(temp, buffer + currentIndex + 3, subLength);
                }
                else
                {
                    subLength = buffer[currentIndex];
 
                    temp = new unsignedchar[subLength];
 
                    memcpy(temp, buffer + currentIndex + 1, subLength);
                }
                temp[subLength] = 0;
                 
                //memcpy(temp, buffer + currentIndex + 1, subLength);
                unsignedint oLength;
                tlvEntity[currentTLVIndex].Sub_TLVEntity = new TLVEntity[1];
                Construct(temp, subLength, tlvEntity[currentTLVIndex].Sub_TLVEntity, oLength);
            }
 
            currentStatus = 'L';
            break;
        case 'L':      
            //判断长度字节的最高位是否为1,如果为1,则该字节为长度扩展字节,由下一个字节开始决定长度
            if((buffer[currentIndex] & 0x80) != 0x80)
            {
                tlvEntity[currentTLVIndex].Length = new unsignedchar[1];
                memcpy(tlvEntity[currentTLVIndex].Length, buffer + currentIndex, 1);
                tlvEntity[currentTLVIndex].Length[1] = 0;
                tlvEntity[currentTLVIndex].LengthSize = 1;
 
                valueSize = tlvEntity[currentTLVIndex].Length[0];
 
                currentIndex += 1;
            }
            else
            {
                //为1的情况
 
                unsignedint lengthSize = buffer[currentIndex] & 0x7f;
                 
                currentIndex += 1; //从下一个字节开始算Length域
 
                for (int index = 0; index < lengthSize; index++)
                {
                    valueSize += buffer[currentIndex + index] << (index * 8); //计算Length域的长度
                }
 
                tlvEntity[currentTLVIndex].Length = new unsignedchar[lengthSize];
                memcpy(tlvEntity[currentTLVIndex].Length, buffer + currentIndex, lengthSize);
                tlvEntity[currentTLVIndex].Length[lengthSize] = 0;
 
                tlvEntity[currentTLVIndex].LengthSize = lengthSize;
 
                currentIndex += lengthSize;
            }
 
            currentStatus = 'V';
            break;
        case 'V':
            tlvEntity[currentTLVIndex].Value = new unsignedchar[valueSize];
            memcpy(tlvEntity[currentTLVIndex].Value, buffer + currentIndex, valueSize);
            tlvEntity[currentTLVIndex].Value[valueSize] = 0;
 
            currentIndex += valueSize;
             
            //进入下一个TLV构造循环
            currentTLVIndex += 1;
 
            currentStatus = 'T';
            break;
        default:
            return;
        }
    }
 
    entityLength = currentTLVIndex;
}
 
// 解析TLV
void TLVPackage::Parse(
    TLVEntity* tlvEntity,
    unsignedint entityLength,
    unsignedchar* buffer,
    unsignedint& bufferLength
    )
{
    int currentIndex = 0;
    int currentTLVIndex = 0;
    unsignedlong valueSize = 0;
 
    while(currentTLVIndex < entityLength)
    {
        valueSize = 0;
        TLVEntity entity = tlvEntity[currentTLVIndex];
         
        memcpy(buffer + currentIndex, entity.Tag, entity.TagSize);  //解析Tag
        currentIndex += entity.TagSize;
 
        for (int index = 0; index < entity.LengthSize; index++)
        {
            valueSize += entity.Length[index] << (index * 8); //计算Length域的长度
        }
        if(valueSize > 127)
        {
            buffer[currentIndex] = 0x80 | entity.LengthSize;
            currentIndex += 1;
        }
         
        memcpy(buffer + currentIndex, entity.Length, entity.LengthSize);    //解析Length
        currentIndex += entity.LengthSize;
        //判断是否包含子嵌套TLV
        if(entity.Sub_TLVEntity == NULL)
        {
            memcpy(buffer + currentIndex, entity.Value, valueSize); //解析Value
            currentIndex += valueSize;
        }
        else
        {
            unsignedint oLength;
            Parse(entity.Sub_TLVEntity, 1, buffer + currentIndex, oLength); //解析子嵌套TLV
            currentIndex += oLength;
        }
 
        currentTLVIndex++;
    }
    buffer[currentIndex] = 0;
    bufferLength = currentIndex;
}

然后写测试程序:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 上发测试数据
unsignedchar requestBuf[] = {
        0x9F, 0x1C, 0x12, 0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32, 0x30, 0x34, 0x30, 0x34,
        0x32, 0x37, 0x31, 0x38, 0x9F, 0x62, 0x01, 0x01, 0x57, 0x12, 0x62, 0x22, 0x89, 0x00, 0x00, 0x02, 0x91,
        0x01, 0xD0, 0x90, 0x32, 0x01, 0x02, 0x47, 0x17, 0x13, 0x00, 0x0F, 0x5F, 0x20, 0x0A, 0x48, 0x55, 0x47,
        0x55, 0x4F, 0x20, 0x4D, 0x49, 0x4E, 0x47, 0x9F, 0x1F, 0x3C, 0x25, 0x39, 0x39, 0x36, 0x32, 0x32, 0x32,
        0x38, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 0x39, 0x31, 0x30, 0x31, 0x5E, 0x47, 0x55, 0x4F, 0x20,
        0x4D, 0x49, 0x4E, 0x47, 0x2F, 0x48, 0x55, 0x5E, 0x30, 0x39, 0x30, 0x33, 0x32, 0x30, 0x31, 0x30, 0x32,
        0x34, 0x37, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 0x38, 0x39, 0x30,
        0x30, 0x3F
};
 
    TLVEntity tlvEntity[TLV_MAX_LENGTH];
    unsignedint tlv_count;
    //构造TLV
    TLVPackage::Construct(requestBuf,sizeof(requestBuf), tlvEntity, tlv_count);
 
    unsignedchar parseBuf[1024];
    unsignedint buf_count;
    //解析TLV
    TLVPackage::Parse(tlvEntity, tlv_count, parseBuf, buf_count);
 
    if(strncmp((char*)parseBuf, (char*)requestBuf,sizeof(requestBuf)) == 0)
    {
        AfxMessageBox("TRUE");
    }
    else
    {
        AfxMessageBox("FALSE");
    }

最后测试结果中,可以得到最后将弹出“TRUE”的对话框。证明构造TLV得到的TLVEntity,再对这个实体进行解析,可以的到解析后的字节数组,最后通过strncmp的方法比较判断,是否原始字节数组和解析后的字节数组是否一致。

 

另外,为了方便C#程序员的使用,我对该C++程序重新改写了一下,得出的结果也是一样的。

TLVEntity.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/// <summary>
    /// TLV实体
    /// </summary>
    public class TLVEntity
    {
        /// <summary>
        /// 标记
        /// </summary>
        public byte[] Tag { get;set; }
 
        /// <summary>
        /// 数据长度
        /// </summary>
        public byte[] Length { get;set; }
 
        /// <summary>
        /// 数据
        /// </summary>
        public byte[] Value { get;set; }
 
        /// <summary>
        /// 标记占用字节数
        /// </summary>
        public int TagSize { get;set; }
 
        /// <summary>
        /// 数据长度占用字节数
        /// </summary>
        public int LengthSize { get;set; }
 
        /// <summary>
        /// 子嵌套TLV实体
        /// </summary>
        public TLVEntity Sub_TLVEntity { get;set; }
    }

以及TLVPackage.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
/// <summary>
    /// TLV打包类
    /// </summary>
    public class TLVPackage
    {
        /// <summary>
        /// 构造TLV
        /// </summary>
        /// <param name="buffer">
        public static List<tlventity> Construct(byte[] buffer)
        {
            List<tlventity> list = new List<tlventity>();
            int currentTLVIndex = 0;
            int currentIndex = 0;
            int currentStatus = 'T';//状态字符
            int valueSize = 0;
 
            TLVEntity tlvEntity = null;
 
            while (currentIndex < buffer.Length)
            {
                switch (currentStatus)
                {
                    case 'T':
                        tlvEntity = new TLVEntity();
                        valueSize = 0;
                        //判断是否单一结构
                        if ((buffer[currentIndex] & 0x20) != 0x20)
                        {
                            tlvEntity.Sub_TLVEntity = null;//单一结构时将子Tag置空【】
                            //判断是否多字节Tag
                            if ((buffer[currentIndex] & 0x1f) == 0x1f)
                            {
                                int endTagIndex = currentIndex;
                                while ((buffer[++endTagIndex] & 0x80) == 0x80) ; //判断第二个字节的最高位是否为1
                                int tagSize = endTagIndex - currentIndex + 1; //计算Tag包含多少字节
 
                                tlvEntity.Tag = new byte[tagSize];
                                Array.Copy(buffer, currentIndex, tlvEntity.Tag, 0, tagSize);
 
                                tlvEntity.TagSize = tagSize;
 
                                currentIndex += tagSize;
                            }
                            else
                            {
                                tlvEntity.Tag = new byte[1];
                                Array.Copy(buffer, currentIndex, tlvEntity.Tag, 0, 1);
 
                                tlvEntity.TagSize = 1;
 
                                currentIndex += 1;
                            }
                        }
                        else
                        {
                            //判断是否多字节Tag
                            if ((buffer[currentIndex] & 0x1f) == 0x1f)
                            {
                                int endTagIndex = currentIndex;
                                while ((buffer[++endTagIndex] & 0x80) == 0x80) ; //判断第二个字节的最高位是否为1
                                int tagSize = endTagIndex - currentIndex + 1; //计算Tag包含多少字节
 
                                tlvEntity.Tag = new byte[tagSize];
                                Array.Copy(buffer, currentIndex, tlvEntity.Tag, 0, tagSize);
 
                                tlvEntity.TagSize = tagSize;
 
                                currentIndex += tagSize;
                            }
                            else
                            {
                                tlvEntity.Tag = new byte[1];
                                Array.Copy(buffer, currentIndex, tlvEntity.Tag, 0, 1);
 
                                tlvEntity.TagSize = 1;
 
                                currentIndex += 1;
                            }
 
                            //分析SubTag
                            int subLength = 0;
 
                            byte[] temp;
                            if ((buffer[currentIndex] & 0x80) == 0x80)
                            {
                                for (int index = 0; index < 2; index++)
                                {
                                    subLength += buffer[currentIndex + 1 + index] << (index * 8); //计算Length域的长度
                                }
 
                                temp = new byte[subLength];
 
                                Array.Copy(buffer, currentIndex + 3, temp, 0, subLength);
                            }
                            else
                            {
                                subLength = buffer[currentIndex];
 
                                temp = new byte[subLength];
 
                                Array.Copy(buffer, currentIndex + 1, temp, 0, subLength);
                            }
 
                            int oLength;
                            tlvEntity.Sub_TLVEntity = new TLVEntity();
                            List<tlventity> tempList = Construct(temp);
                            tlvEntity.Sub_TLVEntity = tempList[0];
                        }
 
                        currentStatus = 'L';
                        break;
                    case 'L':
                        //判断长度字节的最高位是否为1,如果为1,则该字节为长度扩展字节,由下一个字节开始决定长度
                        if ((buffer[currentIndex] & 0x80) != 0x80)
                        {
                            tlvEntity.Length = new byte[1];
                            Array.Copy(buffer, currentIndex, tlvEntity.Length, 0, 1);
 
                            tlvEntity.LengthSize = 1;
 
                            valueSize = tlvEntity.Length[0];
                            currentIndex += 1;
                        }
                        else
                        {
                            //为1的情况
 
                            int lengthSize = buffer[currentIndex] & 0x7f;
 
                            currentIndex += 1; //从下一个字节开始算Length域
 
                            for (int index = 0; index < lengthSize; index++)
                            {
                                valueSize += buffer[currentIndex + index] << (index * 8); //计算Length域的长度
                            }
 
                            tlvEntity.Length = new byte[lengthSize];
                            Array.Copy(buffer, currentIndex, tlvEntity.Length, 0, lengthSize);
 
                            tlvEntity.LengthSize = lengthSize;
 
                            currentIndex += lengthSize;
                        }
 
                        currentStatus = 'V';
                        break;
                    case 'V':
                        tlvEntity.Value = new byte[valueSize];
                        Array.Copy(buffer, currentIndex, tlvEntity.Value, 0, valueSize);
 
                        currentIndex += valueSize;
 
                        //进入下一个TLV构造循环
                        list.Add(tlvEntity);
 
                        currentStatus = 'T';
                        break;
                    default:
                        return new List<tlventity>();
                }
            }
 
            return list;
        }
 
        /// <summary>
        /// 解析TLV
        /// </summary>
        /// <param name="list">
        /// <returns></returns>
        public static byte[] Parse(List<tlventity> list)
        {
            byte[] buffer = new byte[4096];
            int currentIndex = 0;
            int currentTLVIndex = 0;
            int valueSize = 0;
 
            while (currentTLVIndex < list.Count())
            {
                valueSize = 0;
                TLVEntity entity = list[currentTLVIndex];
 
                Array.Copy(entity.Tag, 0, buffer, currentIndex, entity.TagSize);    //解析Tag
 
                currentIndex += entity.TagSize;
 
                for (int index = 0; index < entity.LengthSize; index++)
                {
                    valueSize += entity.Length[index] << (index * 8); //计算Length域的长度
                }
                if (valueSize > 127)
                {
                    buffer[currentIndex] = Convert.ToByte(0x80 | entity.LengthSize);
                    currentIndex += 1;
                }
 
                Array.Copy(entity.Length, 0, buffer, currentIndex, entity.LengthSize);  //解析Length
 
                currentIndex += entity.LengthSize;
                //判断是否包含子嵌套TLV
                if (entity.Sub_TLVEntity == null)
                {
                    Array.Copy(entity.Value, 0, buffer, currentIndex, valueSize);   //解析Value
                    currentIndex += valueSize;
                }
                else
                {
                    byte[] tempBuffer = Parse(new List<tlventity> { entity.Sub_TLVEntity });
                    Array.Copy(tempBuffer, 0, buffer, currentIndex, tempBuffer.Length); //解析子嵌套TLV
                    currentIndex += tempBuffer.Length;
                }
 
                currentTLVIndex++;
            }
 
            byte[] resultBuffer = new byte[currentIndex];
            Array.Copy(buffer, 0, resultBuffer, 0, currentIndex);
 
            return resultBuffer;
        }
    }</tlventity></tlventity></tlventity></tlventity></tlventity></tlventity></tlventity>

接着,写测试程序:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
static byte[] requestBuffer =
        {
            0x9F, 0x1C, 0x82, 0x2C, 0x01,
            0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,
            0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,
            0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,
            0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,
            0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,
            0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,
            0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,
            0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,
            0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,
            0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,0x33, 0x33, 0x30, 0x32, 0x32, 0x37, 0x31, 0x39, 0x36, 0x32,
            0x71, 0x07, 0x9f, 0x19, 0x04, 0x11, 0x22, 0x33, 0x44
        };
 
        static void Main(string[] args)
        {
            Console.WriteLine("待组装的数据包:");
            requestBuffer.ToList().ForEach(o => { Console.Write("{0},","0x" + o.ToString("X")); });
 
            Console.WriteLine("\r\n\r\n开始构造TLV");
            //构造TLV
            List<tlventity> list = TLVPackage.Construct(requestBuffer);
            Console.WriteLine("\r\n构造结束!");
 
            Console.WriteLine("\r\n开始解析TLV");
            //解析TLV
            byte[] responseBuffer = TLVPackage.Parse(list);
            Console.WriteLine("\r\n解析结束!");
 
            Console.WriteLine("\r\n解析结果:");
 
            if (ByteEquals(requestBuffer, responseBuffer))
            {
                Console.WriteLine("Equal!");
            }
            else
            {
                Console.WriteLine("Not Equal!");
            }
 
            Console.ReadKey();
        }</tlventity>

运行结果:

image

 

总结

TLV在数据通信方面,其实运用得很广泛,在应用层数据通信中,如HTTP协议,HTML,XML语言本身定义了一些标签(Body,Head,Script)对数据串行化,接收方再根据标签解析原始数据,通过浏览器展现出来。因此本质上也是属于TLV协议的设计模式。甚至在传输层的TCP,UDP协议,你完全可以通过TLV实现自定义的应用协议。