前言
SOME/IP协议越来越多的用于汽车电子行业中,关于协议详细完全的中文资料却没有,所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块:
1. SOME/IP协议讲解
2. SOME/IP-SD协议讲解
3. python/C++举例调试讲解
4.1.3 Endianess -- 字节序
[PRS_SOMEIP_00368]
Upstream requirements: RS_SOMEIP_00026
All SOME/IP Header Fields shall be encoded in network byte order (big endian). -- Header 由于是基于网络传输 跟随为 网络字节序--大端存贮
[PRS_SOMEIP_00759]
Upstream requirements: RS_SOMEIP_00026
The following fields in the payload of SOME/IP messages shall be encoded in network
byte order (big endian): payload和Header一样的字节序
• the optional length field of extensible structs ([PRS_SOMEIP_00079]),
• the TLV tag ([PRS_SOMEIP_00203]) and the length field ([PRS_SOMEIP_00221]) of
structured datatypes and arguments with identifier and optional members,
• the optional length field for fixed length strings ([PRS_SOMEIP_00760]),
• the length field for dynamic length strings ([PRS_SOMEIP_00089]),
• the optional length field for extensible fixed length arrays ([PRS_SOMEIP_00944]),
• the length field of dynamic length arrays ([PRS_SOMEIP_00376]),
• the length field of unions ([PRS_SOMEIP_00126]),
• and the type field of unions ([PRS_SOMEIP_00129]).
以上说明的是payload哪些变长类型时需要添加length字段,后面会有详细介绍。
[PRS_SOMEIP_00369]
Upstream requirements: RS_SOMEIP_00026
The byte order of the parameters inside the payload shall be defined by configuration.
An exception is the tag for TLV (as defined by [PRS_SOMEIP_00202]
and [PRS_SOMEIP_00203]) which shall have byte order according to
[PRS_SOMEIP_00204] and [PRS_SOMEIP_00759].
payload的数据参数类型和排列顺序应该被定义在配置文件中,这样双方对着配置文件就可以序列化和反序列化了。不过TLV除外--后面讲解
4.1.4 Serialization of Data Structures
The serialization is based on the parameter list defined by the interface specification.
The interface specification defines the exact position of all data structures in the PDU
and has to consider the memory alignment.
Alignment is used to align the beginning of data by inserting padding elements after
the data in order to ensure that the aligned data starts at certain memory addresses.
There are processor architectures which can access data more efficiently (i.e. master)
when they start at addresses which are multiples of a certain number (e.g multiples of
32 Bit).
[PRS_SOMEIP_00611]
Upstream requirements: RS_SOMEIP_00028, RS_SOMEIP_00029
Alignment of data shall be realized by inserting padding elements after the variable
size data if the variable size data is not the last element in the serialized data stream.--强调了变长元素如果不是最后一个元素 必须填充。
这段话主要解释了 SOME/IP 进行数据结构序列化时的对齐规则,其中涉及 数据对齐 (Alignment) 和 填充 (Padding) 机制,重点如下:
1. 序列化 (Serialization) 基于接口定义
"The serialization is based on the parameter list defined by the interface specification."
- 序列化 指的是将内存中的数据转换成一个标准格式的数据流,以便传输或存储。
- 接口规范 (interface specification) 决定了 每个数据结构在 PDU (Protocol Data Unit) 中的具体位置,因此数据的存放方式是 提前规定好的,不能随意调整。
2. 需要考虑数据对齐
"The interface specification defines the exact position of all data structures in the PDU and has to consider the memory alignment."
- PDU (协议数据单元) 是 SOME/IP 传输数据的基本单位。
- 数据对齐 是指 确保数据在特定的内存地址上对齐存放,以优化 CPU 访问效率。
- 这意味着:SOME/IP 不能简单地按顺序存放数据,而是要保证合适的对齐规则,如果不满足对齐要求,就需要填充 (Padding)。
3. 为什么要对齐?
"Alignment is used to align the beginning of data by inserting padding elements after the data in order to ensure that the aligned data starts at certain memory addresses."
- 某些处理器架构 (CPU) 访问特定地址的数据时更高效,比如:
- 32 位数据 (4 字节) 最好存放在 4 的倍数的地址上。
- 64 位数据 (8 字节) 最好存放在 8 的倍数的地址上。
- 如果数据 不对齐,有些 CPU 可能需要 额外的指令 才能正确读取,导致性能下降。
4. 一些架构依赖对齐来提高访问效率
"There are processor architectures which can access data more efficiently (i.e. master) when they start at addresses which are multiples of a certain number (e.g. multiples of 32 Bit)."
- CPU 访问内存时,往往有最佳对齐要求:
- 32 位 (4 字节) 访问时,最优地址是
4
的倍数 - 64 位 (8 字节) 访问时,最优地址是
8
的倍数
- 32 位 (4 字节) 访问时,最优地址是
- 如果数据 没有正确对齐,可能会:
- 触发 CPU 额外的访问操作(如 x86 可能执行 2 次读取)。
- 导致某些 RISC 架构直接崩溃(如某些 ARM 处理器不允许非对齐访问)。
5. SOME/IP 通过插入 Padding 确保对齐
[PRS_SOMEIP_00611] Alignment of data shall be realized by inserting padding elements after the variable size data if the variable size data is not the last element in the serialized data stream.
- 如果一个变量大小的数据 (variable size data) 不是最后一个元素,就需要在后面填充 (Padding) 来确保对齐。
- 这是为了让后续的定长数据 (如 UINT32, UINT64) 能够正确对齐。
💡 关键点:
- 固定大小的数据 (如 UINT32, UINT64) 一般直接对齐存放。
- 变长数组 (variable size array) 后面需要填充 (Padding),以保证下一个数据项正确对齐。
- 如果变长数据是最后一个元素,则可以不填充 Padding(因为没有后续数据需要对齐)。
总结
- SOME/IP 在序列化数据时,会严格按照接口规范定义的顺序存放数据。
- CPU 访问某些特定地址上的数据更高效,因此数据对齐很重要。
- 如果某个变长数组不是最后一个数据,就要在它后面插入 Padding,以保证后续数据的对齐。
- 填充 (Padding) 只是为了对齐,不会影响数据本身的意义。
Note: Please note that the padding value is not defined. -- 填充的值不做定义 随意设置
这个例子中为啥变长数组结束的地址已经是4字节对齐了为啥还要再填充?
关键点:变长数组的长度是不确定的
协议规范规定,变长数组后必须填充 (Padding),除非它是最后一个成员。
这个规则并不依赖于当前变长数组是否对齐,而是为了保证序列化数据的一致性和解析的通用性。
📌 主要原因有两个:
-
协议层面的通用性
- SOME/IP 设计时,要求 所有变长数据 (Variable-size Data) 不是最后一个字段时,必须填充 Padding。
- 这样可以保证 所有固定大小的数据 (如 UINT32, UINT64) 都是按照它们的对齐要求放置的,避免不同情况下处理逻辑的复杂性。
-
防止解析时出现不确定行为
- 变长数组的大小可能会发生变化,比如:
- 如果当前变长数组的长度为 4 字节,你会觉得可以不填充。
- 但如果 数组长度变成 3 字节,那
UINT32
就会变成非对齐存储,需要额外的填充。
- 为了解决这种情况,协议强制规定变长数据后必须填充 Padding,以确保固定大小的数据始终是对齐的。
- 变长数组的大小可能会发生变化,比如:
[PRS_SOMEIP_00569]
Upstream requirements: RS_SOMEIP_00028, RS_SOMEIP_00029
Alignment shall always be calculated from start of SOME/IP message.字段对齐内存计算时必须从整个SOMEIP消息的开始位置计算 包括SOME/IP的header
[PRS_SOMEIP_00612]
Upstream requirements: RS_SOMEIP_00028, RS_SOMEIP_00029
There shall be no padding behind fixed length data elements to ensure alignment of
the following data. 定长字段后面不用添加对齐填充。
Note:
If data behind fixed length data elements shall be padded, this has to be explicitly
considered in the data type definition. 如果定长后有填充 必须单独说明
[PRS_SOMEIP_00613]
Upstream requirements: RS_SOMEIP_00028, RS_SOMEIP_00029
The alignment of data behind variable length data elements shall be 8, 16, 32, 64,
128 or 256. Bits. 填充的长度必须是1、2、4、8、16、32、64字节。
基本类型
The Byte Order is specified for each parameter by configuration.字节序 按照 参数规范定义的排列(上面有讲)
[PRS_SOMEIP_00615]
Upstream requirements: RS_SOMEIP_00030, RS_SOMEIP_00031, RS_SOMEIP_00032
For the evaluation of a Boolean value only the lowest bit of the uint8 is interpreted and
the rest is ignored.
对于布尔数据的类型 仅使用最低为 其它位不考虑
[PRS_SOMEIP_00077]
Upstream requirements: RS_SOMEIP_00033
The SOME/IP implementation shall not automatically insert dummy/padding data.
不能像C语言那样 随便插入 填充字节来内存对齐(网络序列不需要 因为反序列化就是按照字节来解析的 没有内存对齐的烦恼) 结构体中每个成员的的序列化要按照规范要求来(下面有介绍各种情况)
[PRS_SOMEIP_00079]
Upstream requirements: RS_SOMEIP_00033, RS_SOMEIP_00040
An optional length field of 8, 16 or 32 Bit may be inserted in front of the Struct depending on the configuration.
[PRS_SOMEIP_00370]
Upstream requirements: RS_SOMEIP_00033, RS_SOMEIP_00040
The length field of the struct shall describe the number of bytes this struct occupies for SOME/IP transport.
可以在结构体前加上描述结构体长度的字段,这个字段可以是1、2、4字节。---需要客户指定
[PRS_SOMEIP_00712]
Upstream requirements: RS_SOMEIP_00028, RS_SOMEIP_00033
The serialization of structs shall follow the depth-first-traversal of the structured data type.
序列化嵌套结构体 应采用深度优先遍历--按照嵌套的顺序依此序列化。
https://github.com/0voice