SOME/IP 协议详解——序列化
文章目录
- 0. 概述
- 1.基本数据序列化
- 2.字符串序列化
- 2.1 字符串通用规则
- 2.2 固定长度字符串规则
- 2.3 动态长度字符串规则
- 3.结构体序列化
- 4. 带有标识符和可选成员的结构化数据类型
- 5. 数组
- 5.1 固定长度数组
- 5.2 动态长度数组
- 5.3 Enumeration(枚举)
- 5.4 Bitfield(位域)
- 5.5 Union/Variant(联合 / 变体)
- 总结
0. 概述
SOME/IP序列化分为四部分,基本数据序列化,字符串序列化,结构体序列化,数组序列化。
1.基本数据序列化
Type | Description | Size [bit] | Remark |
---|---|---|---|
boolean | TRUE/FALSE value | 8 | FALSE (0), TRUE (1) |
uint8 | unsigned Integer | 8 | |
uint16 | unsigned Integer | 16 | |
uint32 | unsigned Integer | 32 | |
sint8 | signed Integer | 8 | |
sint16 | signed Integer | 16 | |
sint32 | signed Integer | 32 | |
float32 | floating point number | 32 | IEEE 754 binary32 (Single Precision) |
float64 | floating point number | 64 | IEEE 754 binary64 (Double Precision) |
对于每个参数的字节序,是由配置来决定的(大小端顺序)。这就好比是给一群数字 “小朋友” 排队,不同的配置会让他们站成不同的顺序。
在对布尔值进行评估时,只看 uint8 中的最低位,其他位都被忽略。
这些基本数据类型在 SOME/IP 协议中就像是一个个小积木,通过不同的组合和排列,构建起了复杂的数据结构,支撑着整个协议的数据处理和传输功能。
2.字符串序列化
2.1 字符串通用规则
- 编码支持
- 支持不同的 Unicode 编码,包括 UTF - 8、UTF - 16BE 和 UTF - 16LE。
- 字符串终止
- UTF - 16LE 和 UTF - 16BE 字符串应以零字符(‘\0’)终止,且至少有两个 0x00 字节。
- 所有字符串应始终以字节顺序标记(BOM)开始,BOM 应包含在固定长度和动态长度字符串中,用于检测编码。
2.2 固定长度字符串规则
- 字符串终止
- 固定长度字符串也应以 ‘\0’ 字符终止,且字符串长度(包括 ‘\0’ 字节)在数据类型定义中指定,未使用空间用 ‘\0’ 填充,BOM 包含在长度内。
- 长度检查
- 如果固定长度字符串长于预期,反序列化应停止,消息视为格式错误。
- 如果固定长度字符串短于预期但正确以 ‘\0’ 终止,可接受。
- 如果固定长度字符串短于预期且未正确以 ‘\0’ 终止,反序列化应停止,消息视为格式错误。
2.3 动态长度字符串规则
- 长度字段
- 动态长度字符串应以长度字段开始,长度以字节为单位测量,长度字段在 BOM 之前,BOM 包含在长度内,字符串以 ‘\0’ 终止,字符串(包括 ‘\0’ 终止)的最大字节数由数据类型定义得出。
- 长度定义
- 动态长度字符串的长度字段有 8、16 或 32 位可选,由接口规范决定,未指定时默认 32 位。长度字段的值不包括长度字段本身。
- 如果动态长度字符串长于预期,反序列化应停止,消息视为格式错误。
- 替代传输方式
- 除了将应用程序字符串作为带有 BOM 和 ‘\0’ 终止的 SOME/IP 字符串传输外,还可将其作为普通动态长度数组传输(不带 BOM 和 ‘\0’ 终止),但应用程序需自行处理字符串,如编码转换。
概括而言:
定长字符串格式【BOM】【data】【‘\0’】
变长字符串格式【length】【BOM】【data】【‘\0’】
lenth大小默认为4byte,包含BOM,data和结束符的长度总和。
3.结构体序列化
- 总体原则
- 结构体序列化要依循内存布局,像按图施工一样逐个参数序列化到缓冲区,且要考虑内存对齐。
- 示例说明
以几个结构体及其内部成员(如 Struct_1 包含 uint32 a 和 float32 b [2] 等)展示序列化过程,如同按盒子内物品摆放顺序处理。 - 关键规则
- 填充数据:不会自动插入无用填充数据,保证数据紧凑。
- 长度字段:可配置插入 8、16 或 32 位长度字段来标识结构体传输字节数,长度不包含长度字段自身。
- 长度检查处理:接收长度大于定义时只按定义处理,多余跳过;长度小于且无法补全缺失数据时反序列化中止,视为格式错误。
- 序列化顺序:按深度优先遍历顺序进行序列化,确保成员处理无遗漏或重复。
4. 带有标识符和可选成员的结构化数据类型
-
总体目的
- 为了实现更好的前向和后向兼容性,在结构体成员或方法参数前可添加额外的数据标识符(Data ID)。接收方可以通过这些标识符跳过未知成员或参数,保证系统在处理新旧数据时的兼容性。
-
标识符规则
- 唯一性:数据标识符在一个 struct 的直接成员或方法的参数中必须唯一,但不需要在不同 struct 或方法之间保持唯一。
- 配置一致性:对于 struct 同一层级的所有成员,要么全部定义数据标识符,要么全部不定义;对于方法的所有参数,也是如此。
-
数据类型编码
- 除了数据标识符,还使用 “线类型(wire type)” 来编码成员的数据类型,两者共同组成 “标签(tag)”。
- 标签结构:标签长度为两个字节,其布局包含多个部分,包括保留位、线类型、数据标识符等。例如,保留位在第 7 位,线类型在第 6 - 4 位,数据标识符在第 3 - 0 位和第二个字节的全部 8 位。
-
不同数据类型的序列化规则
- 基本数据类型:如果序列化的成员或参数是基本数据类型(线类型 0 - 3)且配置了数据标识符,标签应直接插入在成员或参数前面,并且不插入长度字段。
- 复杂数据类型:如果是复杂数据类型(线类型 4 - 7)且配置了数据标识符,标签应插入在长度字段前面,并且必须插入长度字段。
-
长度字段相关规则
- 长度字段始终包含到 struct 中下一个标签的长度。对于 struct、动态长度字符串、动态长度数组、联合类型等,都有相应的长度字段规则,且这些类型的长度字段大小在配置中应大于 0,并且通常应配置为相同大小,以便在处理未知成员或参数时,接收方能够根据统一的规则来解析数据。
-
可选成员处理
- 序列化器在序列化时,如果可选成员被标记为不可用,不应将其包含在序列化字节流中;反序列化器在反序列化时,应忽略字节流中不存在的可选成员。
-
未知数据处理
- 如果反序列化器读取到未知的数据标识符,它应根据线类型和长度字段的信息跳过未知的成员或参数;如果在字节流中找不到必需的(非可选)成员或参数,反序列化应中止,并将消息视为格式错误。
-
接口版本与序列化兼容性
- 如果对现有服务接口引入带标签的序列化,而之前未使用标签,应增加主要接口版本来指示这一变化。
-
带有标签的序列化示例
5. 数组
5.1 固定长度数组
-
长度定义
- 固定长度数组的长度由数据类型定义确定。可以将其视为相同类型元素的重复排列。
- 例如,一维固定长度数组携带指定数量(n)的相同类型元素,其布局按照顺序依次排列,元素大小乘以元素数量就是数组占用的空间大小。
- 多维固定长度数组的序列化遵循编程语言中的内存布局(行主序)。
-
长度处理与错误情况
- 如果接收到的固定长度数组长度大于预期(根据数据类型定义),只解释指定数量的元素,多余字节根据长度字段跳过。
- 如果长度小于预期且接收方无法提供缺失数据的替代值,反序列化将中止,消息视为格式错误。
5.2 动态长度数组
-
布局与长度字段
- 动态长度数组的布局基于固定长度数组,可以在数组开头使用可选的长度字段来指定数组字节长度。
- 长度字段长度可以是 0、8 位、16 位或 32 位,由配置决定。当长度字段设置为 0 位时,数组元素数量固定,此时相当于固定长度数组。
-长度不包括长度字段本身大小。
-
多维数组特点
-
在多维动态长度数组中,每个不同维度的子数组都有自己的长度字段。
-
如果需要静态分配缓冲区大小,数据类型定义应指定每个维度的最大长度。
-
当测量字节长度时,复杂多维数组在反序列化时可以跳过。
-
SOME/IP 支持同一维度中列和行的不同长度,每个动态长度数组前都需要有长度指示。
-
-
长度处理与错误情况
- 如果动态长度数组长度大于预期,只解释指定数量的元素,多余字节根据长度字段跳过。
5.3 Enumeration(枚举)
- 枚举在 SOME/IP 中不作为独立类型考虑,而是被当作无符号整数数据类型传输。
5.4 Bitfield(位域)
- 位域应作为无符号数据类型(uint8/uint16/uint32)传输,数据类型定义可以指定每个位的名称和值。
5.5 Union/Variant(联合 / 变体)
-
联合用于在网络上传输具有不同数据类型的可选数据,由长度字段、类型选择器和有效负载组成。
-
长度字段定义数据和填充字节的大小(不包括长度字段和类型字段本身),类型字段指定数据类型,有效负载根据类型字段进行序列化。
-
长度字段长度由配置决定,可以是 32 位、16 位、8 位或 0 位,当长度字段为 0 位时,联合中的所有类型必须长度相同。
-
类型字段的值由配置为每个联合单独定义,其中 0 值保留用于空类型(表示空联合),并且是否允许空联合也由配置决定。
总结
整体来说,SOME/IP的序列化和反序列化比较死板,不够灵活。