Loading...
墨滴

jasonj333

2021/08/28  阅读:80  主题:红绯

详解SOME/IP协议文档-2

以下内容来源于AutoSar官网的AUTOSAR_PRS_SOMEIPProtocol文档

SOME/IP Payload

SOME/IP Payload由事件的数据元素或方法的参数组成,大小取决于所使用的传输层协议,对于UDP,payload介于0到1400个字节之间,而由于TCP支持payload分段,所以支持更大的长度

SOME/IP payload应以网络字节顺序编码,也就是大端规则传输

数据结构的序列化

将结构化的数据按照一定规则转换成byte字节流,然后封装到SOME/IP的payload里,发送到网络上,这就是数据结构的序列化

结构化的数据是并行的,而payload数据是串行的

数据结构的序列化就是把并行的结构化数据序列化成串行数据

更进一步地说,结构化数据里的元素的数据类型有可能是字符串,数字,布尔值等等,而payload数据只可能是byte数组

那么怎样才能把包含不同数据类型的结构化数据序列化成byte数组呢,不同的项目有不同的规则

之前遇到的项目,是把结构化数据按照ASN.1的格式进行定义的,那么序列化时也是按ASN.1的规则编码成byte数组

Payload数据序列化基于接口规范定义的参数列表,接口规范定义了PDU中所有数据结构的确切位置,并且必须考虑内存对齐

所以SOME/IP payload数据一要根据项目规范,二还要考虑内存对齐

什么是内存对齐,之前在学习capl中的结构体时涉及过

计算机系统为了简化处理器与内存之间的传输,以及提升读取数据的速度,对数据在内存中的存储的位置进行了限制,要求是某个数k的倍数,这就是所谓的内存对齐

结构体中的元素由于大小不一,就需要设置这个k值,每个元素的长度必须是这个k值的倍数,如果不满足,就需要填充一定的内存空间以满足k值的倍数

设置对齐方式,并不意味着结构体的长度/大小发生了变化

而对于payload里的数据结构,如果某个元素大小可变,且不是序列化数据流中的最后一个元素,则应通过在可变元素数据后插入填充位来实现数据对齐

固定长度数据元素后不应该有填充,如果非要填充,必须在规范中明确

可变长度元素后面的数据对齐应为1、2、4、8、16、32个byte

支持的数据类型

基本数据类型

  • 布尔类型
  • 无符号整数,包括8、16、32、64位
  • 有符号整数,包括8、16、32、64位
  • 浮点数,包括32位和64位

结构化数据类型(结构体)

结构体应按顺序序列化,还需考虑内存对齐

SOME/IP不能自动插入虚拟或填充数据

根据配置情况,可以在结构体前插入长度字段,以表示这个结构体数据在SOME/IP传输时的长度,长度字段的大小为8、16或32位

如果长度字段大小大于结构体长度,则仅反序列化指定的字节,并根据长度字段跳过其他字节,如果长度字段大小小于结构体长度,且接收方无法在本地提供数据来替换,则中止反序列化,并将SOME/IP消息视为格式错误

反序列化是对序列化的反向操作,接收方根据收到的SOME/IP payload进行的解析

带有标识符和可选成员的结构化数据类型和参数

为了兼容之前或之后的版本,可以为结构成员或方法参数添加数据ID,有了这个ID,接收方才会反序列化,这样就可以设置可选成功,同时可以在任意位置添加新的成员

每个数据ID在结构中是唯一的,不能重复,在不同的结构或方法中不需要唯一

结构中同一层级的成员,要么全部定义数据ID,要么全部都不定义,方法中所有参数要么全部定义数据ID,要么全部都不定义

一个元素的tag
一个元素的tag

通过上图,可以看到结构体中一个元素的组成

  • Wire Type

第一个byte的6-4位,它的值表示后面数据的类型

Wire Type 4时长度字段是静态配置的,而5、6、7是忽略静态配置,忽略长度字段的大小,根据Wire Type选择长度字段的大小,5是1个byte,6是2个byte,7是4个byte,可以看上图

  • Data ID

第一个byte的3-0位,和第二个byte的8位,共12位

如果结构的元素或方法的参数配置了Data ID,则应该在序列化字节流中插入tag,也就是下面这个东西

一个元素的tag
还有Strings、Arrays等数据类型

SOME/IP协议规范

SOME/IP支持TCP和UDP传输消息,选择哪种传输协议,后续会讲到

如果服务器和多个客户端进行同一个服务的SOME/IP通信,它会运行同一服务的不同实例,这些实例的消息是通过传输层协议端口映射到该实例上的

也就是说为了辨别不同的实例,就需要用实例的消息的传输层端口来区分

传输层payload里允许有多个SOME/IP消息,根据长度字段确定每个SOME/IP消息

每个SOME/IP payload都应该有自己的SOME/IP首部

一个服务实例可以用以下方式来进行所有方法、事件和通知的通信

  • 最多一个TCP连接
  • 最多一个UDP单播
  • 最多一个UDP多播

UDP绑定

SOME/IP的UDP绑定通过UDP包传输SOME/IP消息来实现

SOME/IP协议不应限制UDP分片的使用

UDP payload里是SOME/IP消息,如果payload太大,在网络层会进行分片,而SOME/IP协议不能限制它的分片功能

对于配置为使用UDP单播通信的服务实例的所有方法、事件和通知,客户端和服务器应使用单个UDP单播连接

这句话的意思是一个单播UDP能实现所有配置为UDP单播通信的方法、事件和通知

一个多播UDP能实现所有配置为UDP多播通信的事件和通知

TCP绑定

SOME/IP的TCP绑定通过TCP报文传输SOME/IP消息来实现

一个单播TCP能实现所有配置为TCP单播通信的方法、事件和通知

这里有几个注意点

  • 客户端在SOME/IP通信前首先需要建立TCP连接
  • 客户端负责在失败时重新建立TCP连接
  • 当需要断开连接时,由客户端发起断开连接请求
  • 当使用TCP连接的所有服务不再可用(停止或超时)时,客户端应关闭TCP连接
  • 服务器在停止所有服务时不应停止TCP连接,给客户端足够的时间来处理控制数据以关闭TCP连接本身
  • 如果客户端没有主动关闭TCP连接,而服务器关闭TCP连接,那么客户端会尝试重新建立连接

上面讲的TCP连接与断开的逻辑只针对SOME/IP的TCP协议而言,并不是标准TCP协议的规范

SOME/IP-TP

记得在前面看到SOME/IP-TP时并不了解其含义,这里就涉及到了

通过UDP传输长度很长的SOME/IP消息

SOME/IP的UDP绑定只能传输直接适合IP数据包的SOME/IP消息

什么意思

就是SOME/IP消息的大小最好能在IP层不需要分片直接传输

如果需要通过UDP传输更大的SOME/IP消息,则应使用SOME/IP-TP

就是说如果SOME/IP消息太大,就要用SOME/IP-TP协议,相当于在SOME/IP层对SOME/IP消息进行分片,这时候的SOME/IP Header就变成了SOME/IP-TP Header

SOME/IP消息太大而不能用UDP绑定直接传输的,称为“原始”SOME/IP消息

在SOME/IP-TP消息中传输的原始SOME/IP消息payload的“片段”称为segments

所有的SOME/IP-TP段必须携带原始消息的Session ID,因此,它们都具有相同的Session-ID

SOME/IP-TP segments应将消息类型的TP-Flag设置为1

就是其中有一位要设置为1,可以回顾下前面的文章

举例

原始SOME/IP消息为

如何分片

SOME/IP-TP消息

最后一条SOME/IP-TP消息

最后一条SOME/IP-TP的More Segment Flag为0,表示这是最后一条分片的SOME/IP消息
最后一条SOME/IP-TP的More Segment Flag为0,表示这是最后一条分片的SOME/IP消息

可以看出,SOME/IP-TP其实是对SOME/IP长消息的分片,SOME/IP-TP的首部相比较SOME/IP的首部,有两个不同点

  • Message Type字段的TP-Flag标志位要设置为1
  • 多了4个字节的字段,用来表示offset、Res和M

发送方行为

发送方应仅对配置为分段的消息进行分段,且按顺序发送

发送方应把More Segment Flag设置为1的所有段都分片成相同的大小,也就是说除了最后一片,其他的分片大小都要相同,都是1392个byte

发送方不得发送重复的分片报文

接收方行为

接收方应根据配置的Message-ID、Protocol-Version、Interface-Version和Message-Type(w/o TP Flag)进行重组

Session ID用于检测下一个要重组的原始消息

这句话说明了什么

说明同一原始SOME/IP消息分片的Segment的Session ID相同,同时它还是接收方重组新的分片的标志

如果接收到具有不同Session-ID的Segment,则接收方应开始新的重组(并可能丢弃未成功重组的旧段)

这句话说明如果收到新的Session ID,而之前的重组还未完成,接收方需要开始新的重组,这时候就会导致之前的还未完成的重组的消息被丢弃

这种情况通常发生在新的消息的分片跑到了旧消息的分片的前面,被接收方收到

只有正确重组的消息才能传递给应用程序

消息的每个分片都有Return Code,只有最后一片的Return Code在重组时被使用

当检测到有丢失的分片时,应该取消之前的重组,这意味着不支持重新排序

接收方还支持覆盖重复的分片以正确重组消息


jasonj333

2021/08/28  阅读:80  主题:红绯

作者介绍

jasonj333