SOME/IP介绍
什么是SOME/IP?
SOME/IP (可扩展服务导向中间件协议,Scalable Service Oriented MiddlewarE over IP)
- ”可扩展“-在不同硬件平台、不同操作系统或嵌入式固件已经不同应用软件的以后设备之间的可扩展性和互操作性
- ”面向服务“-表明它是一种面向服务的基本协议。因此仅当客户端请求或服务器通知特定订阅者时,才在客户端-服务器配置中交换数据 ,这就确保了永远不会浪费带宽,并且仅在需要的时间和地点进行数据通信/交换。
- ”中间件“-它也是一种中间件。即其位于应用层,有自己的通用协议层来处理更具体的操作及应用;
- ”基于IP“-它也是一个基于以太网的协议。 它使用类似的硬件接口,确保高达 100Mbps 的带宽。 同时数据通过中间件(即应用层)通过网络电缆使用 TCP/IP 或 UDP 协议进行通信。 当客户端需要来自服务器的数据时,它可由客户端使用
TCP 协议进行请求。 如果服务器必须将数据传送给所有活动的订阅者,则可通过 UDP 协议传输。 UDP
协议上的数据通信可以是单播、多播或广播。
OSI七层协议模型
首先,我们需要了解在计算机领域的一种标准化网络通信协议框架。也就是OSI七层协议模型,是ISO国际标准化提出的一个试图使各种计算机在世界范围内互连为网络的标准框架。
- (第7层)应用层
位于OSI参考模型层次结构的最顶层,由网络应用实现。这些应用产生要在网络上传输的数据。应用层还为应用服务提供访问网络的窗口,并向用户显示接收到的信息。。该层协议有HTTP(超文本传输协议)、SMTP(电子邮件传输协议)、FTP(文件传输协议)、DNS(用于将域名转换为IP地址的分布式数据库系统,它允许用户通过输入易于记忆的域名来访问互联网上的资源,而无需记住复杂的IP地址)等。 - (第6层)表示层
也叫翻译层。表示层负责提取应用层的数据如文字、图像、音频等,并按照网络传输所需的格式进行转换、加密/解密、压缩。该层协议有JPEG、MPEG、GIF、HTML、ASCII、TLS/SSL(加密保护协议)等。 - (第5层)会话层
负责建立连接,管理连接,终止两个设备之间的会话。提供身份验证和安全性。该层协议有RPC(远程过程调用,用于分布式系统)、NetBIOS(网上基本输入输出系统,用于局域网通信)、PPTP(点对点隧道协议,用于虚拟专网VPN)等. - (第4层)传输层
为应用层提供服务,并从网络层获取服务。传输层负责完整消息的端到端传递,将来自会话层的信息进行分段重组,并提供成功数据传输的确认,在发现错误时重传数据。该层协议有TCP(传输控制协议,有连接可靠)、UDP(用户数据报协议,无连接不可靠)等 - (第3层)网络层
网络层用于将数据从一台主机传输到位于不同网络中的另一台主机。它还负责数据包路由,即从可用的路由中选择传输数据包的最短路径。该层协议IP协议(网际互连协议) - (第2层)数据链路层
负责节点到节点的消息传递。它的主要功能是确保数据在物理层上无误地从一个节点传输到另一个节点。数据链路层将从网络层接收到的数据包进一步划分为帧,并在帧中封装发送者和接收者的MAC地址。 - (第1层)物理层
负责设备之间的实际物理连接。它传输的信息单位是比特,负责从一个节点向另一个节点传输单个比特。
TCP/IP四层or五层模型
是TCP/IP在OSI基础上进一步划分的
SOME/IP的分层结构
基于TCP/IP的五层协议,SOME/IP位于应用层。
SOME/IP的消息类型
SOME/IP通过网络提供面向服务的通信。它基于列出服务提供的功能的服务定义。服务可以由零个或多个Event(事件)、Method(方法)和Field(字段)的组合组成。
Event(事件)
提供数据,这些数据周期性地或在发生更改时从提供程序发送到订阅程序。
发送策略:
- cyclic update 周期发送
例,每过50ms发送一次信息。 - update on change 有变化时发送
例,当车门状态由开启变为关闭时,发送信息。 - epsilon change 变化超过阈值时发送
例,当预测值和当前值之间的差大于阈值时,才发送更新
Method(方法)
为订阅者提供了发出在提供者端执行的远程过程调用的可能性。
-
RR Method(Request/Response)
请求/相应方法,即Clinet客户端发送请求给Server,Server受到请求后,再给Client恢复响应。属于同步调用
-
F&F Method (Fire/Forget)
发射后不管,翻译过来听起来很奇怪吧。实际上Fire/Forget这个词汇最早是描述一种导弹制导方式。即在发射后不需要进一步的外部干预,例如目标照明或有线制导,并且可以在发射器不在目标视线内的情况下击中目标。在这里表示Client客户端只对Server服务器发送请求,无需响应。
Field(字段)
以下三个字段中的一个或多个的组合:
- Notifier 通知 :将有关更改的数据从提供者发送到订阅者
- Getter 获取:订阅者可以调用它来显式地向提供者查询值
- Setter 设置:当订阅者想要改变提供者端的值时,可以调用它。
Field/Notifier与Event的区别:
Field/Notifier的发送策略和Event一致,区别在于当第一订阅成功时, Field/Notifier的Server服务端会主动发送一个字段值,此时Client客户端可以立即获得Field的初始值,不用等待事件触发。
SOME/IP的传输协议
SOME/IP支持两种传输协议:用户数据报协议(UDP)和传输控制协议(TCP)
TCP
TCP添加了额外的功能来实现可靠的通信。TCP不仅处理比特错误,还处理分段、丢失、重复、重新排序和网络拥塞。
UDP
UDP是一种非常精简的传输协议,只支持最重要的功能(多路复用和使用校验和进行错误检测)
在车辆内部,许多应用需要非常短的超时时间才能快速做出反应。使用UDP可以更好地满足这些要求,因为应用程序本身可以处理不太可能发生的错误。例如,在使用循环数据的情况下,最好的方法通常是等待下一次数据传输,而不是尝试修复上一次数据传输。UDP的主要缺点是它不处理分段。因此,只能传输较小的数据块。
使用规则:
- 仅当需要传输非常大的数据块(> 1400 Mbps)并且在错误情况下没有硬延迟要求时,才使用TCP
- 如果需要非常严格的延迟要求(<100 ms)以防止错误,则使用UDP
- 如果需要传输非常大的数据块(> 1400 KB),并且存在错误情况下的硬延迟要求,则将UDP与SOME/IP-TP一起使用
SOME/IP的报文格式
SOME/IP由Header(报文头)和 Payload构成,其中协议头部里的字段是:
-
Message ID (Service ID/Method ID) [32 Bits]
消息ID(服务ID/方法ID)[32位]
报文唯一的标识符 -
Length [32 Bits]
长度[32位]
Length字段后包括数据的长度 -
Request ID (Client ID/Session ID) [32 Bits]
请求ID(客户端ID/会话ID)[32位]
Client ID:区分请求同一服务Service的不同客户端
Session ID:同一客户端请求同一服务Service的次数
-
Protocol Version [8Bits]
协议版本[8位] -
Interface Version [8 Bits]
接口版本[8位] -
Message Type [8 Bits]
消息类型[8位]
值 | 字段 | 描述 |
---|---|---|
0x00 | REQUEST | 期望有响应的请求 |
0x01 | REQUEST_NO_RETURN | 不期望有响应的请求 |
0x02 | NOTIFICATION | 不期望有响应的通知/事件回调请求 |
0x80 | RESPONSE | 响应信息 |
0x81 | ERROR | 错误响应 |
0x20 | TP_REQUEST | 期望有响应的TP请求 |
0x21 | TP_REQUEST_NO_RETURN | 不期望有响应的TP请求 |
0x21 | TP_NOTIFICATION | 通知/事件回调的TP请求 |
0xa0 | TP_RESPONSE | TP响应信息 |
0xa1 | TP_ERROR | 包含错误的TP响应 |
- Return Code [8 Bits]
返回代码[8位]
值 | 字段 | 描述 |
---|---|---|
0x00 | E_OK | 未出现错误 |
0x01 | E_NOT_OK | 出现未知错误 |
0x02 | E_UNKNOWN_SERVICE | 请求的服务ID未知 |
0x03 | RESPE_UNKNOWN_METHODNSE | 请求的方法ID未知,服务ID已知 |
0x04 | E_NOT_READY | 服务ID和方法ID是已知的,应用程序未运行 |
0x05 | E_NOT_REACHABLE | 无法访问运行服务的系统(仅限内部错误代码) |
0x06 | E_TIMEOUT | 发生超时(仅限内部错误代码) |
0x07 | E_WRONG_PROTOCOL_VERSION | SOME/IP协议版本不匹配 |
0x08 | E_WRONG_INTERFACE_VERSION | 服务接口版本不匹配 |
0x09 | E_MALFORMED_MESSAGE | 反序列化错误 |
0x0a | E_WRONG_MESSAGE_TYPE | 报文类型错误(例如,对于定义为REQUEST的方法,为REQUEST_NO_RETURN) |
0x0b | E_E2E_REPEATED | E2E重复计算错误 |
0x0c | E_E2E_WRONG_SEQUENCE | E2E序列化错误 |
0x0d | E_E2E | 没有进一步指明E2E错误 |
0x0e | E_E2E_NOT_AVAILABLE | E2E不可用 |
0x0f | E_E2E_NO_NEW_DATA | 没有E2E计算的新数据 |
0x10 -0x1f | E_E2E_NO_NEW_DATA | 包含错误的TP响应 |
0xa1 | RESERVED | 保留用于一般的SOME/IP错误 |
0x20 -0x5E | RESERVED | 保留服务和方法的特殊错误 |
带E2E通信保护的SOME/IP报文格式:
在返回代码之后增加了E2E报文头
序列化与反序列化
序列化是将数据结构等转换为可保持或传输的字节流格式的过程。
反序列化就是序列化的逆过程,它从存储或传输介质中读取数据,并重建对象的原始状态。
序列化的目的是为了保持传输数据的完整性和可传递性。通过网络发送到另一个接收端。
接口规范定义了PDU中所有参数的确切位置,并考虑了内存对齐。序列化过程不应尝试自动对齐参数,而应按照接口规范中指定的对齐方式进行对齐。
如下图 以含有5个成员的结构体为例子,其中红色部分为变长数组后的剩余字段的填充部分。而固定长度的数据元素后不能有填充。
基本数据类型的序列化
类型 | 描述 | 长度[bit] |
---|---|---|
boolean | 布尔值 | 8 |
uint8 | 无符号8位整数 | 8 |
uint16 | 无符号16位整数 | 16 |
uint32 | 无符号32位整数 | 32 |
uint64 | 无符号64位整数 | 64 |
sint8 | 有符号8位整数 | 8 |
sint16 | 有符号16位整数 | 16 |
sint32 | 有符号32位整数 | 32 |
sint64 | 有符号64位整数 | 64 |
float32 | 单精度浮点数 | 32 |
float64 | 双精度浮点数 | 64 |
以uint32类型的数据0x12345678为例:
-
大端字节序
就是从高位->低位读 类比 人类读数法(如一千两百三十)
32位数划分为4个字节
低地址存高位数,高地址存低位数byte0 byte1 byte2 byte3 0x12 0x34 0x56 0x78 -
小端字节序
机器读数法 从低位->高位读
低地址存低位数,高地址存高位数byte0 byte1 byte2 byte3 0x78 0x56 0x34 0x12
结构体的序列化
结构体成员按顺序序列化
也可增加8、16、32bit的Length Field长度字段表示结构体中数据元素的字节长度,此时结构体内所嵌套的结构体也需增加Length Field字段
字符串序列化
定长和变长字符串 都是以"\0"字符(0x00)结尾。
支持不同的Unicode编码UTF-8/UTF-16BE/UTF-16LE
定长字符串
序列化格式:BOM+数据+结束符
-
UTF-8
以 前三个字节作为BOM(字节顺序标记),一个字节长度结尾(0x00)EFBBBF(UTF-8的BOM) E8BDA6(车) E8BDBD(载) 45(E) 54(T) 48(H) 0x00(结尾)
-
UTF-16BE(大端序) / UTF-16LE(小端序)
以 前两个字节作为BOM,两个字节长度结尾(0x00 0x00)FEFF(UTF-16BE的BOM) 5E8F(序) 5217(列) 5316(化) 0041(A) 0042(B) 0043(C) 0x00 0x00(结尾)
图中红色部分为定长字符串 剩余未占用,用Padding填充。
变长字符串
在定长字符串的基础上,变长字符串在BOM前增加了Length Field长度字段,用来表示动态字符串的字节长度。
序列化格式:
Length Field(从BOM到\0的长度和)+BOM+数据+结束符
如下图所示表达了两个字符串的序列化数据:
第一个 字符串:
000A(表示实际字符串所占用字节长度10bytes) EFBBBF(utf-8的BOM)E6B5AA(浪) E8B4B9(费) 0x00(结尾)
第二个 字符串:
000A(表示实际字符串所占用字节长度10bytes) EFBBBF(utf-8的BOM) 62(b) 61(a) 64(d) 67(g)75(u)79(y) 0x00(结尾)
字符编码 | BOM |
---|---|
UTF-8 | EF BB BF |
UTF-16BE | FE FF |
UTF-16LE | FF FE |
UTF-32BE | 00 00 FE FF |
UTF-32LE | FF FE 00 00 |
数组序列化
定长数组序列化
一维定长数组
LengthField(长度字段,可选)+每个数组元素按顺序序列化…
多维定长数组
LengthField(所有数据的总长度,可选)+按照第一维度的顺序对第二维度数组进行序列化…
eg. uint8 arr[2][4] //未配置长度字段
arr[0][0] arr[0][1] arr[0][2] arr[0][3] //每个元素占一个字节长度
arr[1][0] arr[1][1] arr[1][2] arr[1][3]
变长数组序列化
一维变长数组
LengthField(长度字段,必须配置)+每个数组元素按顺序序列化…
多维变长数组
LengthField(长度字段,必须配置)+按照第一维度的顺序对第二维度数组进行序列化…
eg. uint8 arr[2][4] //配置32位的长度字段(占四个字节长度)
length_field_all = 0x00000010(总长度为16字节)
length_field1 = 0x00000004(第二维第一个元素长度4个字节)
arr[0][0] arr[0][1] arr[0][2] arr[0][3] //每个元素占一个字节长度
length_field2 = 0x00000004(第二维第二个元素长度4个字节)
arr[1][0] arr[1][1] arr[1][2] arr[1][3]
SOME/IP-SD (服务发现/订阅)
SOME/IP-SD报文格式
SOME/IP-SD是基于SOME/IP的报文,主要用于 服务的发现寻址并检测服务实例是否正在运行 以及 发布/订阅 ,通过UDP进行传输,在SOME/IP报头的基础下增加了部分内容,报文格式如下:
#固定值
Service ID: 0xFFFF
Method ID: 0x8100
Length: 32 bit
Client ID: 0x0000
Session ID: 0x0001~0xFFFF (记录会话次数,每次根据用例的发送次数递增)
Protocol Version: 0x01
Interface Version: 0x01
Message Tyoe: 0x02 (通知)
Return Code: 0x00 (E_OK)
在SOME/IP报头的基础下增加了部分内容:
- Flags [8 bit] 标识字段
最高位reboot flag表示重启状态,若为1表示正在重启中,0表示未重启或Session ID完成1~0xFFFF的循环之后此时置0。
//检测重启逻辑
if old.reboot == 0 and new.reboot ==1 then 检测到重启
if old.reboot == 1 and new.reboot ==1 and old.session_id > new.session_id 检测到重启
第二高位unicast flag表示单播标志,若为1表示支持单播,0表示不支持单播
其余为固定为0
eg:1100 0000 (表示正在重启中且支持单播)
-
Reserved [24 bit] 保留字段
预留字段,所有位固定为0 -
Length of Entries Array[32 bit] 入口数组的长度
-
Entries Array 入口数组
有两类 Service Entry和Eventgroup Entry1.Service Entry
针对服务寻址类型报文
名称 | 位 bit | 描述 |
---|---|---|
Type Field | 8 | 用来区分服务寻址的不同场景。 0x00 表示 FindService(发现服务) 0x01 表示 OfferService / StopOfferService(提供/停止提供服务) |
Index 1st options | 8 | 表示第一个option的索引值 |
Index 2st options | 8 | 表示第二个option的索引值 |
#of opt1 | 4 | 表示第一个option的条目数 |
#of opt2 | 4 | 表示第二个option的条目数 |
Service ID | 16 | 标识服务ID。如果是Server端 则通过SdServerServerID配置;如果是Client端 则通过SdClientServerID配置 |
Instance ID | 16 | 实例ID,区分同一服务的不同实例。如果指的是服务的所有服务实例,则将其设置为0xFFFF |
Major Version | 8 | 主要版本 |
TTL | 24 | Entry的生命周期,单位s(秒) 当TTL>0&&Type_Field == 0时,为FindService 当TTL>0&&Type_Field ==1时,为OfferService 当TTL == 0&&Type_Field ==1时,为StopOfferService |
Minor Version | 32 | 次要版本 |
2.Eventgroup Entry
针对事件订阅类报文
名称 | 位 bit | 描述 |
---|---|---|
Type Field | 8 | 用来区分服务订阅的不同场景。 0x06 表示 SubscribeEventgroup / StopSubscribeEventgroup(订阅/停止订阅事件组) 0x07 表示 SubscribeAckEventgroup / SubscribeEventgroupNack(订阅事件组成功/失败响应) |
Index 1st options | 8 | 表示第一个option的索引值 |
Index 2st options | 8 | 表示第二个option的索引值 |
#of opt1 | 4 | 表示第一个option的条目数 |
#of opt2 | 4 | 表示第二个option的条目数 |
Service ID | 16 | 标识服务ID。如果是Server端 则通过SdServerServerID配置;如果是Client端 则通过SdClientServerID配置 |
Instance ID | 16 | 实例ID,区分同一服务的不同实例。对于任何实例,服务实例ID不得设置为0xFFFF。 |
Major Version | 8 | 主要版本 |
TTL | 24 | Entry的生命周期,单位s(秒) 当TTL > 0 && Type_Field == 6时,为SubscribeEventgroup 当TTL > 0 && Type_Field ==7时,为SubscribeAckEventgroup 当TTL == 0 && Type_Field ==6时,为StopSubscribeEventgroup 当TTL == 0 && Type_Field ==7时,为SubscribeEventgroupNack |
Reserved | 12 | 保留位 |
Counter | 4 | 对不同客户端订阅同一事件组的计数 |
Eventgroup ID | 16 | 事件组ID,表示需要订阅的事件组标识符 |
-
Length of Options Array[32 bit] 选项数组的长度
-
Options Array 选项数组
Option是Entry的附加信息(例如IP地址、传输协议、端口号)
主要包含以下几种类型:
1.Endpoint Option 端点选项
由SOME/IP-SD实例用于向相关端点发送信号。端点包括本地IP地址、传输层协议(例如UDP或TCP)和发送方的端口号。这些端口也用于事件和通知事件。
IPv4端点选项
-Length [16bit] 长度字段
设置为0x0009
- Type [8bit] 类型
设置为0x04
- Disc. Flag [1bit] 可丢弃标志
设置为0
- Reserved [7bit] 保留位
设置为0x00
- IPv4-Address [32bit] IPv4地址
应将单播IP地址作为4bytes传输
- Reserved [8bit] 保留位
设置为0x00
- Transport Protocol (L4-Proto)[8bit] L4传输层协议
0x06为TCP,0x11为UDP
- Port Number [16bit] 端口号
第4层协议的端口IPv6端点选项
- Length [16bit] 长度字段
设置为0x0015
- Type [8bit] 类型
设置为0x06
- Disc. Flag [1bit] 可丢弃标志
设置为0
- Reserved [7bit] 保留位
设置为0x00
- IPv6-Address [128bit] IPv6地址
应将单播IP地址作为16bytes传输
- Reserved [8bit] 保留位
设置为0x00
- Transport Protocol (L4-Proto)[8bit] L4传输层协议
0x06为TCP,0x11为UDP
- Port Number [16bit] 端口号
应设置为传输层端口(例如30490)。2.Multicast Option 多播选项
由服务器服务(服务器服务多播端点)或客户端服务(客户端服务多播端点)传输:
是由服务器/客户端服务发送,服务器/客户端指示IPv4多播地址、传输层协议(ISO/OSI第4层)和端口号,在Server端中多播事件和多播通知事件被发送到这些地址,在Client端接收多播事件和多播通知事件。
IPv4多播选项
- Length [16bit] 长度字段
设置为0x0009
- Type [8bit] 类型
设置为0x14
- Disc. Flag [1bit] 可丢弃标志
设置为0
- Reserved [7bit] 保留位
设置为0x00
- IPv4-Address [32bit] IPv4地址
应将单播IP地址作为4bytes传输
- Reserved [8bit] 保留位
设置为0x00
- Transport Protocol (L4-Proto)[8bit] L4传输层协议
0x11为UDP
- Port Number [16bit] 端口号
第4层协议的端口
IPv6多播选项
- Length [16bit] 长度字段
设置为0x0015
- Type [8bit] 类型
设置为0x16
- Disc. Flag [1bit] 可丢弃标志
设置为0
- Reserved [7bit] 保留位
设置为0x00
- IPv6-Address [128bit] IPv6地址
应将单播IP地址作为16bytes传输
- Reserved [8bit] 保留位
设置为0x00
- Transport Protocol (L4-Proto)[8bit] L4传输层协议
0x11为UDP
- Port Number [16bit] 端口号
应设置为传输层端口。3.Configuration Option 配置选项
用于传输任意配置字符串。如服务名称或其配置。
- Length [16bit] 长度字段
配置Option占用的总字节数不包括(Length和Type的长度)
- Type [8bit] 类型
设置为0x01
- Disc. Flag [1bit] 可丢弃标志
若设置为丢弃Option,应为1
- Reserved [7bit] 保留位
设置为0x00
- Configuration String [dyn length] 配置字符串
所携带的配置字符串信息4.Load Balancing Option 负载均衡选项
用于区分服务的不同实例的优先级,以便客户端根据这些设置选择服务实例。
- Length [16bit] 长度字段
设置为0x0005
- Type [8bit] 类型
设置为0x02
- Disc. Flag [1bit] 可丢弃标志
若设置为丢弃Option,应为1
- Reserved [7bit] 保留位
设置为0x00
- Priority [16bit] 优先级
携带此实例的优先级。值越低,优先级越高。
- Weight [16bit] 权重
携带此实例的权重。值越大,被选中概率越高。
以下为不同类型的Entry允许携带的Option类型及个数关系表:
例如,FindService 可以最多可以携带一条Configuration Option,一条Load Balancing Option。
Endpoint | Multicast | Configuration | Load Balancing | |
---|---|---|---|---|
FindService | 0 | 0 | 0-1 | 0-1 |
OfferService | 1-2 | 0 | 0-1 | 0-1 |
StopOffer Service | 1-2 | 0 | 0-1 | 0-1 |
Subscribe Eventgroup | 0-2 | 0-1 | 0-1 | 0-1 |
StopSubscribe Eventgroup | 0-2 | 0-1 | 0-1 | 0-1 |
Subscribe EventgroupAck | 0 | 0-1 | 0-1 | 0-1 |
Subscribe EventgroupNack | 0 | 0 | 0-1 | 0-1 |