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

      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结构实体:

// TLV结构体

struct TLVEntity {

	unsigned char* Tag;			//标记

	unsigned char* Length;		//数据长度

	unsigned char* Value;		//数据

	unsigned int TagSize;		//标记占用字节数

	unsigned int LengthSize;	//数据长度占用字节数

	TLVEntity* Sub_TLVEntity;	//子嵌套TLV实体

};
其中TagSize代表Tag字段的字节长度,LengthSize代表Length的字节长度,这里的Length记住要使用char*,由于前面说过,Length可能包含多个字节,通过多个字节确定Value域的长度,Sub_TLVEntity作为子嵌套的TLV结构体。

      定义一个TLVPackage的打包类:

TLVPackage.h:

// TLV打包类

class TLVPackage

{

public:

	TLVPackage();

	virtual ~TLVPackage();

	//构造TLV实体

	static void Construct(unsigned char* 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);

};

具体方法实现:

// 构造TLV

void TLVPackage:: Construct(

	unsigned char* buffer, 

	unsigned int bufferLength, 

	TLVEntity* tlvEntity, 

	unsigned int& entityLength,

	unsigned int status

	)

{

	int currentTLVIndex = 0;

	int currentIndex = 0;

	int currentStatus = 'T'; //状态字符

	unsigned long 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 unsigned char[tagSize];

					memcpy(tlvEntity[currentTLVIndex].Tag, buffer + currentIndex, tagSize); 

					tlvEntity[currentTLVIndex].Tag[tagSize] = 0;



					tlvEntity[currentTLVIndex].TagSize = tagSize;



					currentIndex += tagSize;

				}

				else

				{

					tlvEntity[currentTLVIndex].Tag = new unsigned char[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 unsigned char[tagSize];

					memcpy(tlvEntity[currentTLVIndex].Tag, buffer + currentIndex, tagSize); 

					tlvEntity[currentTLVIndex].Tag[tagSize] = 0;



					tlvEntity[currentTLVIndex].TagSize = tagSize;



					currentIndex += tagSize;

				}

				else

				{

					tlvEntity[currentTLVIndex].Tag = new unsigned char[1];

					memcpy(tlvEntity[currentTLVIndex].Tag, buffer + currentIndex, 1);

					tlvEntity[currentTLVIndex].Tag[1] = 0;



					tlvEntity[currentTLVIndex].TagSize = 1;



					currentIndex += 1;				

				}



				//分析SubTag

				int subLength = 0;	

				

				unsigned char* temp;

				if((buffer[currentIndex] & 0x80) == 0x80)

				{

					for (int index = 0; index < 2; index++)

					{

						subLength += buffer[currentIndex + 1 + index] << (index * 8); //计算Length域的长度

					}



					temp = new unsigned char[subLength];



					memcpy(temp, buffer + currentIndex + 3, subLength);

				}

				else

				{

					subLength = buffer[currentIndex];



					temp = new unsigned char[subLength];



					memcpy(temp, buffer + currentIndex + 1, subLength);

				}

				temp[subLength] = 0;

				

				//memcpy(temp, buffer + currentIndex + 1, subLength);

				unsigned int 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 unsigned char[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的情况



				unsigned int 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 unsigned char[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 unsigned char[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, 

	unsigned int entityLength, 

	unsigned char* buffer, 

	unsigned int& bufferLength

	)

{

	int currentIndex = 0;

	int currentTLVIndex = 0;

	unsigned long 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

		{

			unsigned int oLength;

			Parse(entity.Sub_TLVEntity, 1, buffer + currentIndex, oLength);	//解析子嵌套TLV

			currentIndex += oLength;

		}



		currentTLVIndex++;

	}

	buffer[currentIndex] = 0;

	bufferLength = currentIndex;

}

然后写测试程序:

// 上发测试数据

unsigned char 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];

	unsigned int tlv_count;

	//构造TLV

	TLVPackage::Construct(requestBuf, sizeof(requestBuf), tlvEntity, tlv_count);



	unsigned char parseBuf[1024];

	unsigned int 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

/// 

    /// TLV实体

    /// 

    public class TLVEntity

    {

        /// 

        /// 标记

        /// 

        public byte[] Tag { get; set; }



        /// 

        /// 数据长度

        /// 

        public byte[] Length { get; set; }



        /// 

        /// 数据

        /// 

        public byte[] Value { get; set; }



        /// 

        /// 标记占用字节数

        /// 

        public int TagSize { get; set; }



        /// 

        /// 数据长度占用字节数

        /// 

        public int LengthSize { get; set; }



        /// 

        /// 子嵌套TLV实体

        /// 

        public TLVEntity Sub_TLVEntity { get; set; }

    }

以及TLVPackage.cs

/// 

    /// TLV打包类

    /// 

    public class TLVPackage

    {

        /// 

        /// 构造TLV

        /// 

        /// 

        public static List
  
    
     
    Construct(byte[] buffer)

        {

            List
   
     
       list = new List 
      
        (); 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 
       
         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 
        
          (); } } return list; } /// 
          /// 解析TLV ///  /// 
          /// 
          public static byte[] Parse(List 
         
           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 
          
            { 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; } } 
           
          
         
        
       
     
  
    

接着,写测试程序:

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
  
    
     
    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();

        }
  
    

运行结果:

image

 

总结

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

 

附上C#源代码:TLVPackageDemo.rar

你可能感兴趣的:(C++)