本文是SOME/IP 官方文档的翻译。原文地址:https://www.autosar.org/fileadmin/standards/R22-11/FO/AUTOSAR_RS_SOMEIPProtocol.pdf
1.引言和概览
2. 协议要求
3. 缩略语和术语
术语/缩略语 | 描述 |
---|---|
Byte Order Mark | 字节顺序标记(byte order mark, BOM)是一个Unicode字符,U+FEFF字节顺序标记(byte order mark, BOM),它作为一个魔数出现在文本流的开头,用于表明所使用的编码 |
Method | 可被调用的方法、过程、函数或子程序 |
Parameters | 方法或事件的输入、输出或输入/输出参数 |
Remote Procedure Call (RPC) | 从一个ECU到另一个ECU的方法调用,使用消息传输 |
Request | 客户端发给服务端用来调用方法(Method)的消息 |
Response | 服务端响应客户端方法调用的消息 |
Request/Response communication | 一次请求/回复过程,也就是RPC |
Event(事件) | 单向数据传输,只在变化时调用或循环调用,从数据的生产者发送到消费者 |
Field | Field(字段)代表一种状态,因此在getter、setter和notifier操作的任何时候都有一个有效值 |
Notification Event | 用字段通知的事件消息 |
Getter | 允许读取字段的请求/响应调用。 |
Setter | 允许对字段进行写访问的请求/响应调用。 |
Service | 零个或多个方法、零个或多个事件、零个或多个字段的逻辑组合。 |
Eventgroup | 一个服务中事件和字段通知事件的逻辑组合,以便允许订阅 |
Service Instance | 一个服务的实现,它可以在车辆上多次存在,也可以在ECU上多次存在 |
Server | 提供服务实例的ECU在这个服务实例的上下文中应该被称为服务器。 |
Client | 在这个服务实例的上下文中,使用服务器服务实例的ECU应该被称为客户端。 |
Fire and Forget | 无回复的请求叫做 解雇并遗忘 |
User Datagram Protocol | 一种传输层协议 |
Union | 一种动态假设不同数据类型的数据结构 |
non-extensible (standard) struct | 序列化时不带标签的结构体。最多可以在结构体末尾以兼容的方式添加新成员,而不能添加可选成员。 |
extensible struct | 用标签序列化的结构体。可以在任意位置以兼容的方式添加新成员,也可以添加可选成员。 |
4. 协议定义
SOME/IP 是一种基于网络的服务导向协议。它基于列出服务提供的功能的服务定义。一个服务可以由零个或多个事件、方法和字段的组合组成。
事件(Events)指由提供者给订阅者,周期性或更改时发送的数据
方法(Methods)为订阅者提供了发出在提供者端执行远程过程调用的可能性
字段(Fields)由下面三种的一个或多个组合而成:
- 一个通知器(notifier),数据发生更改时,由提供者发给订阅者
- 一个getter,它可以被订阅者调用以显式地查询提供者的值
- 一个setter,订阅者在想要更改提供者端上的值时可以调用的setter
字段的通知器和事件的主要区别是事件只在发生变化时发送,字段的通知器在订阅后直接发送数据。
4.1 SOME/IP 消息格式定义(序列化)
序列化描述的是数据以协议数据单元(pdu)的形式表示,作为UDP或TCP消息的有效载荷,在基于ip的车载网络上传输。
4.1.1 SOME/IP 头格式
SOME/IP 头和E2E头格式
4.1.1.1 Message ID[32 bit]
消息ID是一个32位的标识符,用于标识对应用程序方法的RPC调用或者标识一个事件。消息ID在配置的时候,要求具备唯一性。
4.1.1.2 Method ID[15 bit]
方法ID是消息ID的一部分
Service ID [16 Bit] | 0 [1 Bit] | Method ID [last 15 Bit] |
---|
4.1.1.3 Event ID[15 bit]
事件组是一个服务中事件和字段通知事件的逻辑组合,以便允许订阅。事件ID结构如下表所示:
Service ID [16 Bit] | 1 [1 Bit] | Event ID [last 15 Bit] |
---|
- 空事件组无法使用
- 事件或者字段通知都必须映射到至少一个事件组里
4.1.1.4 Length [32 Bit]
该字段表示从"Request ID"字段开始,到SOME/IP报文结束的字节长度。
4.1.1.5 Request ID [32 Bit]
请求ID允许提供者和订阅者区分同一方法、事件、读取方法或设置方法的多个并行使用。
- 请求ID对于提供者-订阅者-组合(即一次订阅)必须是唯一的
- 在生成响应消息时,提供者应将请求ID从请求复制到响应消息中
- 请求id必须在响应到达或预期不再到达(超时)之前不能重复使用。
请求ID的结果如下表所示
Client ID [16 Bit] | Session ID [last 15 Bit] |
---|
注意:这意味着ECU的实现者可以根据其实现的需要定义客户端id,而提供者不需要知道此布局或定义,因为他只需在响应中复制完整的请求id。
- 客户端ID是ECU内部调用客户端的唯一标识符。客户端ID允许ECU区分来自多个客户端对同一方法的调用。
- 会话ID是一个唯一的标识符,允许区分来自同一发送者的顺序消息或请求。
- 客户端ID还应通过可配置的前缀或固定值(例如,客户端ID的最重要字节为诊断地址,或为给定应用/SW-C配置的客户端ID),在整个车辆中保持唯一性。
例如:
Client ID Prefix [8 Bits] | Client ID [8 Bits] | Session ID [16 Bits] |
---|
- 如果Session Handling未激活,则Session ID设置为0x00。
- 如果Session Handling已激活,会话ID应设置为[0x1, 0xFFFF]范围内的值
- 如果Session Handling已激活,会话ID应根据各自的用例递增(专用用例的详细信息包含在单独的规格项中
- 请求/响应方法应使用带有会话id的会话处理。会话ID应该在每次调用后递增。
- 当会话ID达到0xFFFF时,它将绕到0x01重新开始
- 对于请求/响应方法,如果响应的会话ID与请求的会话ID不匹配,订阅者必须忽略响应
- 对于通知消息,如果会话处理不活跃,则接收方忽略会话ID
- 对于通知消息,接收方应根据各自的用例处理会话ID(专用用例的详细信息包含在单独的规范项中(例如,[PRS_SOMEIP_00741]),在会话处理是活跃的情况下。
4.1.1.6 Protocol Version [8 Bit]
Protocol Version 固定为1
4.1.1.7 Interface Version [8 Bit]
接口版本应该是一个8位字段,包含服务接口的主要版本。
4.1.1.8 Message Type [8 Bit]
“消息类型”字段用于区分不同类型的消息,应包含以下值
Number | Value | Description |
---|---|---|
0x00 | Request | A request expecting a response (even void) |
0x01 | REQUEST_NO_RETURN | A fire&forget request |
0x02 | NOTIFICATION | A request of a notification/event callback expecting no response |
0x80 | RESPONSE | The response message |
0x81 | ERROR | The response containing an error |
0x20 | TP_REQUEST | A TP request expecting a response (even void) |
0x21 | TP_REQUEST_NO_RETURN | A TP fire&forget request |
0x22 | TP_NOTIFICATION | A TP request of a notification/event callback expecting no response |
0xa0 | TP_RESPONSE | The TP response message |
0xa1 | TP_ERROR | The TP response containing an error |
消息类型的第三高位(=0x20)被称为TP-Flag,应该设置为1,表示当前的SOME/IP消息是一个段。消息类型的其他位按本节中指定的方式设置。
消息类型请求(0x00)的段具有消息类型(0x20),消息类型响应(0x80)的段具有消息类型(0xa0),等等。具体操作请参见(4.2.1.4章)
4.1.1.9 Return Code [8 Bit]
返回码应使用,表示请求是否已成功处理。为了简化标题布局,每条消息都传输字段返回码。特定消息类型允许返回的代码如下表所示
Message Type | Allowed Return Codes |
---|---|
REQUEST | N/A set to 0x00 (E_OK) |
REQUEST_NO_RETURN | N/A set to 0x00 (E_OK) |
NOTIFICATION | N/A set to 0x00 (E_OK) |
RESPONSE | See Return Codes in [PRS_SOMEIP_00191] |
ERROR | See Return Codes in [PRS_SOMEIP_00191]. Shall not be 0x00 (E_OK) |
4.1.1.10 Payload [variable size]
在有效载荷字段中携带参数。参数的序列化将在下一节中指定。
SOME/IP有效载荷字段的大小取决于所使用的传输协议。使用UDP, SOME/IP有效载荷应该在0到1400字节之间。为了允许协议栈的未来更改(例如更改为IPv6或添加安全手段),需要限制为1400字节。由于TCP支持有效载荷分段,因此自动支持更大的有效载荷。
有效负载可能由事件的数据元素或方法的参数组成。
4.1.2 Endianess(字节顺序)
- 所有的SOME/IP头字段应以网络字节序(大端序)编码
- 有效载荷内部参数的字节顺序应由配置定义
4.1.3 Serialization of Data Structures(数据结构序列化)
序列化基于接口规范定义的参数列表。接口规范定义了PDU中所有数据结构的确切位置,必须考虑内存对齐。
Alignment用于对齐数据的起始位置,在数据之后插入填充元素,以确保对齐的数据从某些内存地址开始。
有些处理器架构可以更有效地访问数据(例如master),当它们的起始地址是某个数字的倍数时(例如32位的倍数)。
- 如果可变大小数据不是序列化数据流中的最后一个元素,则通过在可变大小数据之后插入填充元素来实现数据的对齐。
数据结构序列化章节涉及的内容比较复杂,个人认为刚开始接触SOME/IP,没必要花费太大精力在这一章节,先学会如何使用SOME/IP即可。
4.2 SOME/IP 协议规范
本章描述SOME/IP的远程过程调用(RPC)、事件通知和错误处理。
4.2.1 Transport Protocol Bindings(传输协议绑定)
SOME/IP 目前支持UDP和TCP传输,这节将介绍TCP/UDP 绑定,而第六章将讨论如何选择传输协议。
如果一个服务端运行同一服务的不同实例,属于不同服务实例的消息将通过服务器端的传输协议端口映射到该服务实例。更多细节见4.2.1.3章节。
所有传输协议绑定都应支持在传输层PDU(即UDP包或TCP段)中传输多个SOME/IP消息。
接收SOME/IP的实现方法(implementation)应能够接收由UDP或TCP传输的未对齐SOME/IP消息
理由是:
当在UDP或TCP中传输多个SOME/IP有效载荷时,只有当每个有效载荷的长度是对齐大小的倍数(例如32位)时,才能保证有效载荷的对齐。
首部格式允许在一个数据包中传输多个SOME/IP消息。SOME/IP实现通过SOME/IP长度字段来标识SOME/IP消息的结束。根据数据包长度字段,SOME/IP将确定数据包中是否有额外的SOME/IP消息。这适用于UDP和TCP传输。
每个SOME/IP载荷必须有自己的SOME/IP 头
一个服务实例可以使用以下设置来通信它的所有方法、事件和通知:
- 最多一个TCP连接(up to one TCP connection)
- 最多一个UDP单播连接(up to one UDP unicast connection)
- 最多一个UDP多播连接(up to one UDP multicast connection)
4.2.1.1 UDP Binding
UDP 绑定需要使用UDP传输协议数据包实现,SOME/IP协议不能限制UPD分片的使用。
对于配置为使用UDP单播通信的服务实例的所有方法、事件和通知,客户端和服务器应使用一个UDP单播连接。
对于配置为使用UDP多播通信的服务实例的所有方法、事件和通知,客户端和服务器应使用一个UDP多播连接。
4.2.1.2 TCP Binding
SOME/IP的TCP绑定很大程度上是基于UDP绑定的。与UDP绑定相比,TCP绑定允许更大的SOME/IP消息,并利用了TCP的健壮性特性(处理丢失、重排序、重复等)。为了降低延迟和反应时间,应关闭内格尔算法(TCP_NODELAY)。
当TCP链接丢失时,未建立的请求应按超时处理。由于TCP处理可靠性,SOME/IP不需要额外的可靠性手段。
对于配置为使用TCP通信的服务实例的所有方法、事件和通知,客户端和服务器应该使用一个TCP连接。
当传输第一个方法调用或客户端试图接收第一个通知时,TCP连接应由客户端打开。
-
当TCP链接失效时,由客户端负责重新建立TCP链接;当TCP链接不再被请求时,应有客户端关闭TCP链接;当使用TCP连接的所有服务不再可用时(停止或超时),客户端应关闭TCP连接。
-
服务器在停止所有服务时,不应停止TCP连接。给客户端足够的时间来处理控制数据,从而关闭TCP连接。因为当服务器在客户端意识到不再需要TCP之前关闭TCP连接时,客户端将尝试重新建立TCP连接。
- 允许使用魔法缓存(Magic Cookies)重新同步TCP流
为了允许测试工具识别通过TCP传输的SOME/IP消息的边界,可以在TCP消息流上以固定距离将SOME/IP魔法缓存消息插入SOME/IP消息中。
魔法缓存消息应该具备以下字段:
-
客户端 -> 服务端:
- Message ID (Service ID/Method ID): 0xFFFF 0000
- Length: 0x0000 0008
- Request ID (Client ID/Session ID): 0xDEAD BEEF
- Protocol Version: 0x01
- Interface Version: 0x01
- Message Type: 0x01
- Return Code: 0x00
-
服务端 -> 客户端;
- Message ID (Service ID/Method ID): 0xFFFF 8000
- Length: 0x0000 0008
- Request ID (Client ID/Session ID): 0xDEAD BEEF
- Protocol Version: 0x01
- Interface Version: 0x01
- Message Type: 0x02
- Return Code: 0x00
4.2.1.3 多服务实例(Multiple Service-Instances)
同一个服务的服务实例通过不同的实例id识别。应支持多个服务实例驻留在不同的ECU上,以及一个或多个服务的多个服务实例驻留在单个ECU上。
虽然不同服务的多个服务实例应该能够共享使用的传输层协议的相同端口,但在单个ECU上的同一个服务的多个服务实例应该对每个服务实例使用不同的端口–因为虽然实例ID用于SOME/IP SD,但它们不包含在SOME/IP 头中
服务实例可以通过服务ID和套接字(即ip地址、传输协议(UDP/TCP)和端口号)的组合来识别。建议UDP和TCP实例使用相同的端口号。如果一个服务实例使用UDP端口x,则只有该服务的实例,而同一服务的另一个实例不应该完全使用TCP端口x。
4.2.1.4 使用UDP传输大型SOME/IP消息(SOME/IP-TP)
SOME/IP-TP是指SOME/IP Transport Protocol。当SOME/IP消息很大(大于32KB),我们需要SOME/IP-TP进行传输。SOME/IP消息太大,不能直接通过UDP绑定传输,称为“原始”SOME/IP消息。在SOME/IP- tp消息中传输的原始SOME/IP消息负载的“片段”称为“段”。
只有在需要传输非常大的数据块时才使用TCP (>1400字节),并且在存在错误的情况下没有硬延迟要求
这节内容使用不多,我们先跳过
4.2.2 请求/回复 通讯(R&R communication)
SOME/IP 使用的R&R 通讯模型是最常用的通讯模型
SOME/IP 请求消息需要包含有效载荷和头,因此客户端需要做以下工作:
- 构建有效载荷
- 设置客户端想要调用的消息ID(message ID)
- 设置长度字段为8字节(这8字节是SOME/IP header长度)+序列化有效载荷的长度
- 设置请求ID(Request ID)为唯一数字(仅对客户端唯一)
- 设置协议版本
- 设置交互版本(Interface Version)
- 设置消息类型(Message Type)
- 设置返回码
为了构造请求消息的有效负载,方法的所有input或inout参数应按照方法签名内参数的顺序进行序列化。
服务端回复报文的头部基于客户端请求报文的头部,它需要做到以下工作;
- 构建有效载荷
- 从请求报文中获取消息ID
- 设置长度字段为8字节+新有效载荷的大小
- 从请求报文中获取Request ID
- 设置消息类型为0x80(Response)或者0x81(ERROR)
服务端再未受到对应请求报文时,不能发送回复报文
4.2.3 无回复通讯(Fire&Forget Communication)
客户端也可以发送一种不需要回复的请求,这种报文的主要结构有:
- 有效载荷
- Message ID
- 长度(8+序列号有效载荷的长度)
- Request ID(可选)
- 协议版本
- 交互版本
- 消息类型0x01
- 返回码为0x00
4.2.4 通知事件(Notification Events)
因为客户端和服务端是订阅和发布的关系,所以通知是指服务端向客户端发布一项服务。客户端订阅服务后,当该服务出现了值更新或者一个事件发生,服务端就会向客户端发送一个报文。
SOME/IP仅仅用来传输报文,具体的订阅/发布机制,需要参考SOME/IP-SD协议
发送“通知(Notification)”类消息,服务端需要做以下工作:
- 构建有效载荷
- 设置消息ID
- 设置长度字段为8+序列化有效载荷的长度
- 设置客户端ID(client ID)为0x00。在有会话处理的场景里,服务端发出的通知消息里的会话ID需要每次发送后自动加1
- 设置协议版本
- 设置交互版本
- 设置消息类型为0x02–Notification
- 设置返回码为0x00
当同一ECU上存在多个订阅客户端时,系统应处理通知的复制,以便在通信介质上保存传输。特别是使用多播消息传输通知时,这一点尤其重要。
4.2.4.1 通知报文的传输策略
- 固定周期发送
- 更新即发送
- 微变发送。当变化值超过一个确定的值时进行发送
4.2.5 场(Fields)
一个场代表一种状态,它有一个有效值。在订阅后立即订阅该字段的消费者将该字段值作为初始事件获取。(The consumers subscribing for the field instantly after subscription get the field value as an initial event)。
- 场(Field)必须包含getter、setter、 notifier。至少包含一个getter、一个setter、一个notifier
- 场里的getter,getter request消息里有效载荷为空,getter response的有效载荷为场的值
- 场里的setter,setter request消息里有效载荷是场要被设置的值,而response 这是实际收到的场要设置的值。如果对请求有效负载的值进行了调整(例如,因为超出了限制),则调整后的值将在响应有效负载中传输
- 场里的notifier,当客户端订阅了场后,notifier会发送一个事件报文给客户端场的值
- 场里的值由变化时,notifier会发送一个事件报文,这个报文会遵从事件报文的规则
4.2.6 错误处理
SOME/IP 支持两种不同的错误处理机制:
- 方法的响应消息中的返回代码(Return Codes in the Response Messages of methods)
- 故障消息(Explicit Error Messages)
基于你的配置信息,来决定使用哪种机制
4.2.6.1 返回码
返回码字段必须是UINT8
SOME/IP协议中定义的返回码如下表所示;
ID | Name | Description |
---|---|---|
0x00 | E_OK | No error occurred |
0x01 | E_NOT_OK | An unspecified error occurred |
0x02 | E_UNKNOWN_SERVICE | The requested Service ID is unknown. |
0x03 | E_UNKNOWN_METHOD | The requested Method ID is unknown. Service ID is unknown. |
0x04 | E_NOT_READY | Service ID and Method ID are known. Application not running. |
0x05 | E_NOT_REACHABLE | System running the service is not reachable (internal error code only). |
0x06 | E_TIMEOUT | A timeout occurred (internal error code only). |
0x07 | E_WRONG_PROTOCOL_VERSION | Version of SOME/IP protocol not supported |
0x08 | E_WRONG_INTERFACE_VERSION | Interface version mismatch |
0x09 | E_MALFORMED_MESSAGE | Deserialization error, so that payload cannot be deserialized. |
0x0a | E_WRONG_MESSAGE_TYPE | An unexpected message type was received (e.g.REQUEST_NO_RETURN for a method defined as REQUEST). |
0x0b | E_E2E_REPEATED | Repeated E2E calculation error |
0x0c | E_E2E_WRONG_SEQUENCE | Wrong E2E sequence error |
0x0d | E_E2E | Not further specified E2E error |
0x0e | E_E2E_NOT_AVAILABLE | E2E not available |
0x0f | E_E2E_NO_NEW_DATA | No new data for E2E calculation present. |
0x10 -0x1f | RESERVED | Reserved for generic SOME/IP errors. These errors will be specified in future versions of this document. |
0x20 -0x5E | RESERVED | Reserved for specific errors of services and methods. These errors are specified by the interface specification. |
4.2.6.2 异常消息(Error Message)
为了更灵活地处理错误,SOME/IP允许针对错误消息使用不同的消息布局,而不是使用响应消息的消息布局。异常消息的布局推荐如下:
- 特定异常的联合(Union)。至少需要存在一个不带字段的通用异常。
- 动态长度异常描述字符串
集合(Union)提供了在将来以类型安全的方式添加新异常的灵活性。该字符串用于传输人类可读的异常描述,以简化测试和调试。
事件/通知报文的接收方不能返回异常消息
Fire&forget报文的接收方不能返回异常消息
对于请求/响应方法,异常消息将复制SOME/IP报头的字段(即消息ID、请求ID和接口版本),但不复制有效载荷。此外,消息类型和返回代码必须设置为适当的值。
4.2.6.3 异常处理概览
异常处理流程概览如下图所以:
SOME/IP消息应通过错误处理进行检查。这不包括基于应用程序的错误处理,而只包括消息传递和RPC中的错误处理。
4.2.6.4 通信异常和通信异常处理
在考虑RPC消息的传输时,存在不同的可靠性语义:
- Maybe,消息可能到达通信伙伴
- At least once,消息至少到达通信伙伴一次
- Exactly once,消息只到达通信伙伴一次
虽然不同的实现可能实现不同的方法,但SOME/IP目前在使用UDP绑定时实现“可能”可靠性,而在使用TCP绑定时实现“恰好一次”可靠性。进一步的错误处理留给应用程序。对于“可能”的可靠性,当使用请求/响应通信结合UDP作为传输协议时,只需要一个超时。下图显示了“可能”可靠性的状态机。客户端的SOME/IP实现必须等待指定超时的响应。如果超时发生,某些/IP将向客户端应用程序发送E_TIMEOUT信号。
4.3 交互版本的兼容性
接口版本标识有效载荷的格式。
有效载荷格式受以下因素影响:服务接口规范、序列化配置(例如:可变大小数组的使用、长度字段的大小、填充、TLV、SOME/IP-TP)
5. 配置参数
不在本文档介绍
6. 协议使用范围
6.1 选择传输层协议
SOME/IP支持UDP (User Datagram Protocol)和TCP (Transmission Control Protocol)协议。UDP是一个非常精简的传输协议,只支持最重要的功能(多路复用和使用校验和的错误检测),而TCP为实现可靠的通信增加了额外的功能。TCP不仅可以处理比特错误,还可以处理分段、丢失、重复、重新排序和网络拥塞。在车辆内部,许多应用程序需要非常短的超时才能快速做出反应。使用UDP可以更好地满足这些需求,因为应用程序本身可以处理不太可能发生的错误事件。例如,在循环数据的用例中,等待下一个数据传输而不是尝试修复最后一个数据传输通常是最好的方法。UDP的主要缺点是它不处理分段。因此,只能传输较小的数据块。
- 只有在需要传输非常大的数据块时才使用TCP (>1400字节),并且在存在错误的情况下没有硬延迟要求
- 使用UDP针对那些对时延要求高的场景(<100ms)
- 如果需要传输非常大的数据块,则使用UDP和SOME/IP-TP (>1400字节)和存在错误时的硬延迟要求
- 当外部传输或传输机制(网络文件系统、APIX链接、1722等)更适合用例时,请尝试使用它们。在这种情况下,SOME/IP可以传输文件句柄或类似的标识符。这给了设计者额外的自由(例如在缓存方面)。
6.2 传输CAN和FlexRay消息
SOME/IP应该允许隧道(tunnel)CAN和FlexRay帧。然而,Message ID空间需要在两个用例之间进行协调。完整的SOME/IP报头应用于传输/隧道CAN/FlexRay
6.3 填充结构体
如果需要填充,接口设计者应在数据类型的定义中插入保留/填充元素(如果需要对齐),因为SOME/IP实现不会自动添加这种填充
6.4 SOME/IP 的安全
服务端可以限制来自客户端的链接。服务器可以强制执行通信策略,以保护服务器免受恶意或未经授权的客户端攻击。也就是说,服务器可能会拒绝订阅事件组,或者拒绝未授权的方法调用。
客户端也可以限制来自服务端的链接。客户端可以执行通信策略来保护客户端免受恶意服务器的攻击。即客户端可以拒绝与未经授权的服务器通信。