文章目录
1 摘要
前文介绍了SOME/IP-SD协议的定义与作用、通信流程简述以及报文的结构简单介绍,见如下链接:
车载以太网网络测试-27【SOME/IP-SD简述】
本文接着来详细剖析 SOME/IP-SD 报文中 Length of Entries Array
、Entries Array
、Length of Options Array
和 Options Array
这四个关键字段。它们在车载以太网的服务发现机制中扮演着核心角色。
2 核心概念回顾:SOME/IP-SD (Service Discovery)
- 目的: 让 ECU (电子控制单元) 能够自动发现网络上的服务(如传感器服务、诊断服务、娱乐服务等)、了解服务的状态(是否可用)、服务的元数据(如版本、部署实例)、服务所在的位置(IP地址、端口)以及如何订阅事件组。
- 机制: 基于 UDP/IP(通常使用多播地址
239.255.0.0
/16 用于发现,单播用于特定响应),使用 SOME/IP 头封装 SD 消息。 - 关键功能:
- Offer Service: 服务实例主动宣告其存在。
- Stop Offer Service: 服务实例宣告停止服务。
- Subscribe Eventgroup: 客户端订阅感兴趣的事件组。
- Stop Subscribe Eventgroup: 客户端停止订阅事件组。
- Subscribe Eventgroup Ack: 服务端确认客户端订阅。
- Find Service: 客户端主动查找特定服务(可选,更多依靠被动监听
Offer Service
)。
2.1 Entries Array & Length of Entries Array
定义:
Length of Entries Array
(UInt32): 表示紧接着的Entries Array
的总长度(以字节为单位)。这个字段告诉解析器后面有多少字节的数据属于条目数组。Entries Array
: 包含一个或多个Service Entry
或Eventgroup Entry
的结构化数据块。这些条目描述了服务的“核心意图”,例如“我在提供一个服务”、“我在停止提供服务”、“我想订阅某个事件组”、“我确认了订阅”等。每个Entry
的结构是固定的。
单个 Entry 结构详解:
字段名称 数据类型 长度(字节) 说明 Entry Type UInt8 1 标识条目的类型: - 0x00
:Find Service
-0x01
:Offer Service
-0x06
:Subscribe Eventgroup
-0x07
:Stop Offer Service
(或Offer Service
中带停止标记) -0x08
:Stop Subscribe Eventgroup
-0x09
:Subscribe Eventgroup Ack
(Nack)Index 1 UInt8 1 第一个 Option 索引: 指向 Options Array
中第Index 1
个位置上的选项。此索引通常关联一个Endpoint
(通信端点) 或IPV4 Endpoint
/IPV6 Endpoint
选项,指明提供该服务或事件组的 IP 地址和端口。 索引从 1 开始!0
表示无关联选项。Index 2 UInt8 1 第二个 Option 索引: 指向 Options Array
中第Index 2
个位置上的选项。此索引通常关联一个额外的选项,如Load Balancing
(负载均衡) 或Configuration
(特定配置),尤其是对于Offer Service
。索引从 1 开始!0
表示无关联选项。Number of Options 1/2 UInt8 1 预留,通常置 0。SOME/IP-SD 规范中定义了其结构,但实践中通常为 0
或忽略。Service ID UInt16 2 标识所提供的服务或要查找/订阅的服务。如 0x0101
可能代表车身控制服务。Instance ID UInt16 2 标识服务的具体实例。一个服务可以有多个实例(如左后车门控制、右后车门控制)。 TTL UInt32 4 Time To Live (生存时间): - 对于 Offer Service
: 宣告消息的有效期(秒)。接收者应在此时间内收到新的Offer
或Refresh
(Offer
重发),否则认为服务下线。常用值如3
秒,10
秒。 - 对于Stop Offer Service
:0
。 - 对于Find Service
:0
- 对于Subscribe Eventgroup
:请求订阅的时间窗口。Major Version UInt8 1 服务的接口主版本号( Offer Service
)/期望的版本号(Find Service
/Subscribe
)。主要版本不兼容通常表示无法通信。Minor Version UInt32 4 服务的接口次版本号( Offer Service
)/最小接受的次版本号(Find Service
/Subscribe
)。次版本号通常向后兼容。(Reserved) - 4 保留字节(置 0x0000
)。Options Bitfield Bitfield 标志位(在 Subscribe Eventgroup
中): -Bit 0-7
:Eventgroup ID
(标识要订阅的具体事件组ID) -Bit 8-12
: 预留(置0
) -Bit 13
:ACK
(置1
表示要求服务端回复Subscribe Eventgroup Ack
) -Bit 14
:RESET
(置1
表示在错误恢复后清除之前的订阅状态) -Bit 15
:Entry State
(与Subscribe Eventgroup Ack
相关)OR****保留(在Service Entry
中): -0x0000
(置0
)。(Eventgroup ID) UInt16 2 仅存在于 Eventgroup Entry
(Subscribe
,Subscribe Ack
,Stop Subscribe
) 类型中! 标识要操作的事件组 ID。对于Service Entry
(Offer
,Find
,Stop Offer
), 上述的 2 字节作为保留(置0x0000
)。CRC UInt16 2 循环冗余校验: 用于检测 Entry
自身在传输中的错误(常用算法如 CRC8/XOR,由规范或配置约定)。作用:
- 声明意图:
Entry Type
核心描述了这条 SD 消息想做什么(提供、查找、订阅等)。 - 标识服务:
Service ID
,Instance ID
精确指定目标服务实例。 - 控制生命周期:
TTL
管理服务可用性信息的刷新和超时。 - 关联位置/配置:
Index 1
和Index 2
通过索引指向Options Array
中包含了实现该意图所需的额外具体信息(地址、端口、配置)。 - 处理事件组订阅: 对于事件组相关条目,指定要订阅的事件组 ID 和订阅控制标志(
ACK
,RESET
)。 - 确保完整性:
CRC
提供基本的错误检测。
- 声明意图:
使用场景:
- 服务启动/上线 (ECU A): ECU A 发送
Offer Service
Entry (Type=0x01) 宣告其提供的Service ID
/Instance ID
,设置TTL
为 N 秒,Index 1
指向包含IPV4 Endpoint
的Options Array
项,宣告其 IP 和端口。它会周期性地重发(刷新)此消息。 - 服务下线/停止 (ECU A): ECU A 发送
Stop Offer Service
Entry (Type=0x07 或带有停止标记的 Type=0x01) 宣告其Service ID
/Instance ID
将停止,设置TTL=0
。 - 客户端订阅事件 (ECU B): ECU B (已通过
Offer
知道服务位置) 发送Subscribe Eventgroup
Entry (Type=0x06),指定目标Service ID
/Instance ID
,设置所需的Eventgroup ID
和标志位(如ACK=1
要求确认),Index 1
指向包含其自身用于接收事件的IPV4 Endpoint
的Options Array
项(告知服务端往哪里推送事件)。 - 服务端确认订阅 (ECU A): ECU A 收到订阅请求后,发送
Subscribe Eventgroup Ack
Entry (Type=0x09) 响应给 ECU B,使用相同的Service ID
/Instance ID
/Eventgroup ID
。Index 1
通常指向其自身提供事件的服务端点 (Offer Service 中的那个)。Entry State
位指示订阅是否成功 (0
成功,1
失败如找不到事件组)。 - 客户端查找服务 (ECU C, 可选): ECU C 发送
Find Service
Entry (Type=0x00),指定要查找的Service ID
/Instance ID
(和版本),设置TTL=0
。匹配的服务实例会响应Offer Service
。 - 客户端停止订阅 (ECU B): ECU B 发送
Stop Subscribe Eventgroup
Entry (Type=0x08)。
- 服务启动/上线 (ECU A): ECU A 发送
2.2 Options Array & Length of Options Array
定义:
Length of Options Array
(UInt32): 表示紧接着的Options Array
的总长度(以字节为单位)。这个字段告诉解析器后面有多少字节的数据属于选项数组。Options Array
: 包含一个或多个Option Record
的结构化数据块。每个Option Record
提供Entries Array
中条目所需的“详细补充信息”,主要是通信地址和额外的配置参数。
单个 Option Record 结构详解:
字段名称 数据类型 长度(字节) 说明 Length UInt16 2 此 Option Record
的总长度(包含Length
字段自身),以字节为单位。Type UInt8 1 标识选项的类型: - 0x04
:IPv4 Endpoint
(最常用!) -0x06
:IPv6 Endpoint
-0x09
:Load Balancing
-0x10
:IPv4 Multicast
(用于事件组多播) -0x11
:IPv6 Multicast
-0x14
:IPv4 SD Endpoint
-0x16
:IPv6 SD Endpoint
-0x21
:Configuration
(服务特定配置) -0x81
:IPv4 Endpoint with MAC
-0x82
:IPv6 Endpoint with MAC
Reserved 1 UInt8 1 预留(通常置 0
)Reserved 2 UInt16 2 预留(通常置 0
)… Data … Varied L - 8 选项负载数据: 根据 Type
字段定义的结构。CRC UInt16 2 循环冗余校验: 用于检测 Option Record
自身在传输中的错误(常用算法如 CRC8/XOR,由规范或配置约定)。注意:Length
字段的值包含最后这 2 字节 CRC。关键 Option Record 详解 (以最常见的
0x04: IPv4 Endpoint
为例):字段名称 数据类型 长度(字节) 说明 (上述公共头) 8 Length=20
,Type=0x04
,Reserved=0
,Reserved=0
IPv4 Address UInt32 (BE) 4 大端序 IPv4 地址(如 0xC0A80164
= 192.168.1.100)Reserved UInt8 1 置 0
Protocol UInt8 1 通信协议: - 0x06
: TCP -0x11
: UDPPort Number UInt16 (BE) 2 大端序 端口号(如 0x7D00
= 32000)(CRC) UInt16 2 Length
=2(Length) + 1(Type) + 1(R1) + 2(R2) + 4(IP) + 1(R) + 1(Proto) + 2(Port) + 2(CRC) = 16
? 错误!Length
是整个记录的字节数。 正确计算:Length
=2(Len Field) + 1(Type) + 1(R1) + 2(R2) + 4(IP) + 1(Res) + 1(Proto) + 2(Port) + 2(CRC)
=2 + 1 + 1 + 2 + 4 + 1 + 1 + 2 + 2
= 16 字节。所以Length
字段的值应该是0x0010
(16)。作用:
- 提供位置信息:
IPv4/IPv6 Endpoint
/Multicast
选项是核心,提供提供服务的 ECU 的 IP 地址、协议和端口号,或用于接收事件的多播地址和端口。 - 提供配置信息:
Load Balancing
,Configuration
选项提供附加参数。负载均衡选项(如Priority
和Weight
)帮助客户端在多个提供相同服务实例的 ECU 之间选择最优的。 - 模块化和复用: 关键作用!一个
Endpoint
选项可以被Entries Array
中的多个不同条目引用。例如:- 一个
Offer Service
Entry 引用一个IPv4 Endpoint
(A) 提供方法调用。 - 同一个服务可能有一个
Subscribe Eventgroup Ack
Entry 引用同一个IPv4 Endpoint
(A) 来指明从哪里推送事件(单播)。 - 同一个服务可能还有一个
Subscribe Eventgroup
Entry 引用一个IPv4 Multicast
选项 (B) 来指明接收事件的多播组(多播)。
- 一个
- 可扩展性: 新的选项类型可以在规范更新中定义,以适应未来的需求。
- 确保完整性:
CRC
提供基本的错误检测。
- 提供位置信息:
使用场景:
- 声明服务地址:
Offer Service
Entry 通过Index 1
关联一个IPv4 Endpoint
Option,告知其他 ECU 其服务方法的调用地址(通常是单播地址)。 - 声明事件发布地址: 服务端在
Subscribe Eventgroup Ack
Entry 中通过Index 1
关联:IPv4 Endpoint
选项(单播发送事件)- 或
IPv4 Multicast
选项(多播发送事件)
- 声明客户端事件接收地址: 客户端在
Subscribe Eventgroup
Entry 中通过Index 1
关联一个IPv4 Endpoint
Option,告知服务端应该把事件发送到它的哪个 IP 和端口(或者指定一个多播组)。 - 声明服务发现地址:
IPv4 SD Endpoint
选项可用于在复杂网络拓扑中指定用于交换 SD 消息的特定接口(较少使用)。 - 负载均衡:
Offer Service
Entry 通过Index 2
关联一个Load Balancing
选项(优先级Priority
, 权重Weight
),与其他提供相同Service ID
/Instance ID
的 ECU 竞争时供客户端决策。 - 服务特定配置:
Configuration
选项可用于传递供应商特定的服务参数。
- 声明服务地址:
2.3 协同工作流程
发送者组装 SOME/IP-SD 报文:
- 为本次消息需要表达的核心意图(如宣告一个服务)创建
Entries Array
。例如:一个Offer Service
Entry。 - 为这些 Entry 所需的附加信息创建
Options Array
。例如:一个IPv4 Endpoint
Option。 - 在 Entry 中设置
Index 1
(或Index 2
)为指向Options Array
中相应 Option 的索引(从 1 开始)。 - 计算
Entries Array
的总字节数,填入Length of Entries Array
。 - 计算
Options Array
的总字节数,填入Length of Options Array
。 - 计算每个 Entry 和每个 Option 的
CRC
。 - 封装在 SOME/IP 头(Message Type 为
0x02
- Notification / 事件类型;Service ID0xFFFF
, Method ID0x8100
)和 UDP/IP 头中。
- 为本次消息需要表达的核心意图(如宣告一个服务)创建
接收者解析 SOME/IP-SD 报文:
- 先读取
Length of Entries Array
(L1),然后读取接下来的 L1 个字节作为Entries Array
。 - 根据
Length of Entries Array
读取结束后,读取Length of Options Array
(L2),然后读取接下来的 L2 个字节作为Options Array
。 - 解析
Entries Array
中的每个 Entry:- 根据
Entry Type
判断意图。 - 根据
Service ID
和Instance ID
确定目标服务实例。 - 根据
Index 1
的索引值 N,去Options Array
- 根据
- 先读取
3 车载控制器的应用示例
以车载以太网中的一个典型场景为例,说明控制单元(ECU)之间如何通过SOME/IP-SD协议进行服务发现和订阅,然后进行报文交互。
场景: 智能座舱域控制器 (Cockpit Domain Controller - CDC) 需要从车身域控制器 (Body Domain Controller - BDC) 获取当前四个车窗的状态(开度百分比)。
架构简述:
- 服务提供者 (Provider): 车身域控制器 (BDC)。它拥有并提供
WindowStatusService
服务。这个服务包含一个GetWindowStatus
方法(请求/响应)和一个WindowStatusChanged
事件(发布/订阅)。 - 服务消费者 (Consumer): 智能座舱域控制器 (CDC)。它需要知道车窗状态(可能在仪表盘或中控屏显示)。
- 传输协议: 基于TCP/IP。假设服务使用TCP端口
52000
。 - 通信协议: SOME/IP over Ethernet。
- 服务提供者 (Provider): 车身域控制器 (BDC)。它拥有并提供
服务发现报文交互 (SOME/IP-SD):
步骤 1: BDC (提供者) 广播服务可用性 (OfferService)
当BDC启动或WindowStatusService
服务变为可用时,它会周期性地(或事件触发)向本地网络广播/组播SOME/IP-SD OfferService
报文。[SOME/IP-SD] OfferService Message (From BDC): * Entry Type: 0x00 (Offer Service) * Service ID: 0x5001 (假设分配给 WindowStatusService 的ID) * Instance ID: 0x0001 (此服务的第一个实例) * Major Version: 0x01 * Minor Version: 0x00000000 (初始版本) * TTL: 30 seconds (服务提供30秒有效) // 实际上后续会刷新 * Endpoint Options: * IPv4 Endpoint Option: * IP Address: 192.168.90.101 (BDC的IP) * Transport Protocol: 0x06 (TCP) * Port Number: 52000 (服务监听端口)
这个报文告诉网络上的所有节点:“192.168.90.101的52000端口上提供了一个ID为0x5001的服务实例”。
步骤 2: CDC (消费者) 订阅事件 (SubscribeEventgroup)
CDC收到OfferService
报文后,了解到BDC提供了所需服务。CDC对服务中的WindowStatusChanged
事件(假设该事件被分组到Eventgroup ID 0x8001)感兴趣,因此它向BDC发送SubscribeEventgroup
报文来订阅这个事件。[SOME/IP-SD] SubscribeEventgroup Message (From CDC to BDC): * Entry Type: 0x06 (Subscribe Eventgroup) * Service ID: 0x5001 * Instance ID: 0x0001 * Eventgroup ID: 0x8001 (包含 WindowStatusChanged 事件的事件组) * Major Version: 0x01 (必须与Offer一致) * TTL: 60 seconds (订阅请求60秒有效,BDC需在此时间内确认或响应) // 实际实现中BDC的TTL定义可能不同 * Counter: 0x00 (初始计数器) * Endpoint Option: * IPv4 Endpoint Option: * IP Address: 192.168.90.102 (CDC的IP) // 通知提供者往哪里推送事件 * Transport Protocol: 0x06 (TCP) // 约定订阅通道协议 * Port Number: 0xD2C7 (54311, CDC用于接收事件的临时端口) // 通常是动态端口
步骤 3: BDC (提供者) 确认订阅 (SubscribeEventgroupAck / OfferService + Eventgroup)
BDC收到CDC的订阅请求后,会发送一个确认报文。在SOME/IP-SD中,通常通过再次发送OfferService
消息,并包含对应的Eventgroup
信息来间接确认订阅(虽然也有SubscribeEventgroupAck
,但OfferService刷新是常见方式)。[SOME/IP-SD] OfferService Message (From BDC, 回复订阅): // 与初始Offer类似,但增加了Eventgroup状态 * Entry Type: 0x00 (Offer Service) * Service ID: 0x5001 * Instance ID: 0x0001 * Major Version: 0x01 * Minor Version: 0x00000000 * TTL: 30 seconds (刷新TTL) * Endpoint Options: ... (BDC自身端点) * Additional Entry: * Entry Type: 0x01 (Eventgroup) // 表示此服务包含该事件组 * Service ID: 0x5001 * Instance ID: 0x0001 * Eventgroup ID: 0x8001 * Eventgroup State: ... (通常包含订阅信息状态)
这个更新后的
OfferService
告诉CDC(以及网络上的节点),服务0x5001实例0x0001的事件组0x8001是有效的,并且CDC的订阅已被接受。随后,BDC将开始向CDC指定的端点192.168.90.102:54311
推送WindowStatusChanged
事件。
服务数据报文交互 (SOME/IP):
现在服务发现和订阅已经完成,真正的服务数据交互可以通过直接的TCP连接进行。建立TCP连接 (可选但典型):
CDC作为客户端,向BDC的服务端点(192.168.90.101:52000
)发起TCP连接建立请求(3次握手:SYN, SYN-ACK, ACK)。连接建立成功。场景 1: CDC 主动获取当前车窗状态 (请求/响应 - GetWindowStatus)
CDC可能需要在启动时或事件丢失时主动获取一次完整状态。[SOME/IP] Request Message (From CDC to BDC on TCP): * Message ID: 0x5001xxxx (Service ID 0x5001, Method ID 0xYYYY = GetWindowStatus) * Length: [根据请求载荷计算] * Request ID: 0xCAFE0001 (Client ID + Session ID - 由CDC生成) * Protocol Version: 0x01 * Interface Version: 0x01 * Message Type: 0x00 (REQUEST) // 期望回复 * Return Code: 0x00 (E_OK) * Payload: (可选的请求参数,例如指定某个车窗?此示例可能为空)
BDC收到请求后,执行读取操作并回复:
[SOME/IP] Response Message (From BDC to CDC on TCP): * Message ID: 0x5001xxxx (Service ID 0x5001, Method ID 0xYYYY = GetWindowStatus) * Length: [根据响应载荷计算] * Request ID: 0xCAFE0001 (必须与请求一致) * Protocol Version: 0x01 * Interface Version: 0x01 * Message Type: 0x80 (RESPONSE) * Return Code: 0x00 (E_OK) // 成功 * Payload: (包含四个车窗的开度百分比,例如 FL: 100%, FR: 0%, RL: 50%, RR: 75%)
场景 2: BDC 主动推送车窗状态变更 (事件通知 - WindowStatusChanged)
当任何车窗的开度状态发生改变时(如用户按动按钮),BDC作为服务提供者,会通过之前约定的订阅通道
(通常是建立好的TCP连接,虽然SD事件推送也可用UDP但TCP常见)向CDC推送事件。[SOME/IP] Notification Message (From BDC to CDC on TCP to port 54311): * Message ID: 0x5001zzzz (Service ID 0x5001, Event ID 0xZZZZ = WindowStatusChanged) * Length: [根据载荷计算] * Request ID: 0x80000000 (SERVER ID + Session ID - Server ID常为0x8000) // 服务器主动发起的通知 * Protocol Version: 0x01 * Interface Version: 0x01 * Message Type: 0x02 (NOTIFICATION) // 纯通知,不期望回复 * Return Code: 0x00 (E_OK) * Payload: (包含状态改变的车窗索引和新的开度百分比,例如 ID=2(FR), Status=50%)
CDC收到此
NOTIFICATION
报文后,解析Payload,得知右侧前窗开度变成了50%,并据此更新座舱显示屏上的信息。
总结流程图:
关键点:
- SD报文是基础: 所有服务交互的前提是服务提供者广播其存在(
OfferService
),消费者订阅感兴趣的部分(SubscribeEventgroup
),并通过SD报文交换端点信息。 - 数据报文是核心业务:
REQUEST/RESPONSE
用于同步调用(获取数据或执行操作),NOTIFICATION
用于异步事件推送(状态改变通知)。 - TCP连接: 通常基于SD交换的端点信息建立TCP连接用于可靠的数据传输。服务的监听端口和事件的接收端口可以相同也可以不同(如示例)。
- SOME/IP Header: ALL报文都以SOME/IP Header开头,包含关键元数据(Service/Method/Event ID, Message Type, Request ID, Return Code等)。
- Payload格式:
Request
/Response
/Notification
的Payload格式由服务的IDL(接口描述语言)严格定义。只有解析方知道如何正确解包(需要AUTOSAR ARXML模型或类似的描述文件支持)。 - 实际复杂性: 真实报文包含更多的字段(如Flags, More Segments等)和更复杂的逻辑(错误处理、服务状态管理、多播管理等),以上示例做了高度简化以突出核心流程。
这个例子清晰地展示了从服务发现(广播与订阅)到具体服务方法调用(请求/响应)和事件订阅(通知)的车载以太网SOME/IP通信流程。
4 总结
以上主要介绍了 SOME/IP-SD 报文中 Length of Entries Array
、Entries Array
、Length of Options Array
和 Options Array
这四个关键字段,并以智能座舱域控制器与车身域控制器的交互过程为例进行了介绍,希望能对大家理解SOME/IP-SD 有所帮助!