SOME/IP协议详解「2.1.8·序列化:TLV简述|Tag Length Value」
点击返回雪云飞星的SOME/IP协议详解「总目录」
1 什么是TLV
TLV是Tag Length Value的简称,是someip序列化的一种格式,会有部分车厂在使用,但并不是主流。我们简单讲解一下,让大家知道这个干什么的,不对细节做进一步分析。与之前讲过的所有的类型的序列化格式有所区别,tlv还会再加一层标签,对每个数据进行单独标识,方便管理。标签可以在两个地方加:
- someip服务接口参数
- 某参数定义的struct里的成员
2 TLV格式
从下图中可以看到,如果光看蓝色部分,就是和前面章节中讲解的序列化方式是一样的,而这个主要加了2 bytes的tag头。一个someip报文里可以有很多这样的数据。可以看出,tag+length+数据的形式就在字节流中将每个数据划分成了一段,形成了一个链表,如果不想要该tag的数据,就可以通过length直接跳过去,甚至不用再反序列化(注意的一点是,这里length无论是静态动态数据类型,只要不是基础数据类型都必须要有长度域,以便能通过长度域找到下一个数据) 再说一下上面图中的tag头,主要是3部分组成,1bit的res保留,3bits的wire type,和12bits的data ID:
-
wire type: wire type用来指示后续的长度域占用几个bytes,如果是基础数据类型,没有长度域,其余类型都必须有长度域
wire type | 数据类型 |
---|
0 | 8 bit长度的基础数据类型,没有长度域 | 1 | 16 bit长度的基础数据类型,没有长度域 | 2 | 32 bit长度的基础数据类型,没有长度域 | 3 | 64 bit长度的基础数据类型,没有长度域 | 4 | 复杂数据类型,length域的字节数根据数据类型定义决定 | 5 | 复杂数据类型,length域的字节数固定为1byte | 6 | 复杂数据类型,length域的字节数固定为2byte | 7 | 复杂数据类型,length域的字节数固定为4byte |
-
data ID: data ID对于每一层级的数据要唯一,比如有一个2维度嵌套的struct,那么每一维度都可以使用data ID = 1,但是同一维度ID不能相同 typedef struct {
uint8 a;
uint16 b;
struct {
uint8 d;
uint8 e;
} c;
} testType;
3 服务接口参数的TLV
假如有一个服务接口为:
function(uint8 A, uint16 B, struct C);
我们统一使用wire type = 5的方式进行序列话,那么序列化后三个接口参数的效果如图
4 结构体的TLV
某些参数中会包含到结构体,结构体也可以添加tag,比如在上面例子的基础上进行延伸
typedef struct {
uint8 a;
uint16 b;
struct {
uint8 d;
uint8 e;
} c;
} testType;
function(uint8 A, uint16 B, testType C);
那么序列化图如下:
需要注意几点:
- struct中每一维度可以配置使用tlv或者不使用,如上面的例子中a b c就没有使用tlv,但是c里面的元素d e就使用了tlv
- struct打上tag后,可以对由应用层指定不需要传输的数据不进行序列化,只序列化部分数据传输出去即可(比如某些数据一直没有变动,可以不进行传输)
- 服务参数打上tag后,也必须传输,不能跳过,因为接口入参个数是固定的,不能减少
- 加上tag后,传输参数的顺序就可以变更了,不必要按照定义的顺序进行
- data ID的值是可以配置的,不必非要是1,2,3;可以是3,19,100这样的随机值,只要不重复即可
- 使用tlv格式后,默认不对动态数据末尾填充对齐
点击返回雪云飞星的SOME/IP协议详解「总目录」
|