车载以太网网络测试-28【SOME/IP-SD】2

发布于:2025-07-04 ⋅ 阅读:(18) ⋅ 点赞:(0)

1 摘要

前文介绍了SOME/IP-SD协议的定义与作用、通信流程简述以及报文的结构简单介绍,见如下链接:
车载以太网网络测试-27【SOME/IP-SD简述】

本文接着来详细剖析 SOME/IP-SD 报文中 Length of Entries ArrayEntries ArrayLength of Options ArrayOptions 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 EntryEventgroup 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: 宣告消息的有效期(秒)。接收者应在此时间内收到新的 OfferRefresh (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 1Index 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 EndpointOptions 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 EndpointOptions Array 项(告知服务端往哪里推送事件)。
    • 服务端确认订阅 (ECU A): ECU A 收到订阅请求后,发送 Subscribe Eventgroup Ack Entry (Type=0x09) 响应给 ECU B,使用相同的 Service ID/Instance ID/Eventgroup IDIndex 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)。

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: UDP
    Port 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 选项提供附加参数。负载均衡选项(如 PriorityWeight)帮助客户端在多个提供相同服务实例的 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 协同工作流程

  1. 发送者组装 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 ID 0xFFFF, Method ID 0x8100)和 UDP/IP 头中。
  2. 接收者解析 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 IDInstance ID 确定目标服务实例。
      • 根据 Index 1 的索引值 N,去 Options Array

3 车载控制器的应用示例

以车载以太网中的一个典型场景为例,说明控制单元(ECU)之间如何通过SOME/IP-SD协议进行服务发现和订阅,然后进行报文交互。

场景: 智能座舱域控制器 (Cockpit Domain Controller - CDC) 需要从车身域控制器 (Body Domain Controller - BDC) 获取当前四个车窗的状态(开度百分比)。

  1. 架构简述:

    • 服务提供者 (Provider): 车身域控制器 (BDC)。它拥有并提供WindowStatusService服务。这个服务包含一个GetWindowStatus方法(请求/响应)和一个WindowStatusChanged事件(发布/订阅)。
    • 服务消费者 (Consumer): 智能座舱域控制器 (CDC)。它需要知道车窗状态(可能在仪表盘或中控屏显示)。
    • 传输协议: 基于TCP/IP。假设服务使用TCP端口 52000
    • 通信协议: SOME/IP over Ethernet。
  2. 服务发现报文交互 (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事件。

  3. 服务数据报文交互 (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%,并据此更新座舱显示屏上的信息。

总结流程图:

BDC (Server) CDC (Client) (1) SOME/IP-SD: OfferService(广播) Service:0x5001, IP:Port (2) SOME/IP-SD: SubscribeEventgroup Eventgroup:0x8001, CDC_Evt_IP:Port Ports: BDC:52000, CDC:54311 (3) SOME/IP: Request(GetWindowStatus) (4) SOME/IP: Notification(WindowStatusChanged) 当车窗状态改变时 BDC (Server) CDC (Client)

关键点:

  1. SD报文是基础: 所有服务交互的前提是服务提供者广播其存在(OfferService),消费者订阅感兴趣的部分(SubscribeEventgroup),并通过SD报文交换端点信息。
  2. 数据报文是核心业务: REQUEST/RESPONSE 用于同步调用(获取数据或执行操作),NOTIFICATION 用于异步事件推送(状态改变通知)。
  3. TCP连接: 通常基于SD交换的端点信息建立TCP连接用于可靠的数据传输。服务的监听端口和事件的接收端口可以相同也可以不同(如示例)。
  4. SOME/IP Header: ALL报文都以SOME/IP Header开头,包含关键元数据(Service/Method/Event ID, Message Type, Request ID, Return Code等)。
  5. Payload格式: Request/Response/Notification的Payload格式由服务的IDL(接口描述语言)严格定义。只有解析方知道如何正确解包(需要AUTOSAR ARXML模型或类似的描述文件支持)。
  6. 实际复杂性: 真实报文包含更多的字段(如Flags, More Segments等)和更复杂的逻辑(错误处理、服务状态管理、多播管理等),以上示例做了高度简化以突出核心流程。

这个例子清晰地展示了从服务发现(广播与订阅)到具体服务方法调用(请求/响应)和事件订阅(通知)的车载以太网SOME/IP通信流程。

4 总结

以上主要介绍了 SOME/IP-SD 报文中 Length of Entries ArrayEntries ArrayLength of Options ArrayOptions Array 这四个关键字段,并以智能座舱域控制器与车身域控制器的交互过程为例进行了介绍,希望能对大家理解SOME/IP-SD 有所帮助!


网站公告

今日签到

点亮在社区的每一天
去签到