SOME/IP 协议详解——远程过程调用(RPC)
文章目录
- 1. 传输协议绑定
- 1.1 UDP 绑定
- 1.2 TCP 绑定
- 1.3 多服务实例
- 1.4 通过 UDP 传输大型 SOME/IP 消息(SOME/IP - TP)
- 2. 请求 / 响应通信
- 2.1 客户端请求消息构造
- 2.2 服务器响应消息构建
- 2.3 请求 / 响应交互规则
- 3. Fire&Forget 通信
-
- 4. 通知事件
- 4.1 服务器通知消息构造
- 4.2 通知消息的发送策略
- 5. 字段
- 6. 错误处理
- 6.1 返回码
- 6.2 错误消息
- 6.3 错误处理概述
- 6.4 通信错误及处理
1. 传输协议绑定
1.1 UDP 绑定
- 传输方式:SOME/IP 协议利用 UDP 传输消息时,直接将 SOME/IP 消息封装在 UDP 数据包内。这意味着 SOME/IP 消息作为 UDP 数据包的有效载荷进行传输,UDP 为其提供基本的传输服务。
- 分片限制:SOME/IP 协议本身不限制 UDP 的分片功能。UDP 分片是将一个较大的 UDP 数据包分割成多个较小的片段进行传输,在网络层可能会因为链路层的最大传输单元(MTU)限制而发生。例如,当一个 SOME/IP 消息较大,超过了网络链路层的 MTU 时,UDP 会自动将其分片,而 SOME/IP 协议允许这种分片操作。
- 消息识别与头部独立性:在单个 UDP 数据包中可能包含多个 SOME/IP 消息。接收方通过 SOME/IP 消息头部中的长度字段来确定每个消息的边界。每个 SOME/IP 有效载荷都有自己独立的 SOME/IP 头部,这使得每个消息在 UDP 数据包内能够被独立识别和处理,即便它们在同一个 UDP 数据包中传输。
1.2 TCP 绑定
- 与 UDP 绑定的关系及特性增强:TCP 绑定基于 UDP 绑定构建,在其基础上提供了更强大的功能。TCP 本身具有可靠性特性,能够处理如数据丢失、重复、乱序以及网络拥塞等问题,SOME/IP 利用 TCP 的这些特性来确保更可靠的消息传输,尤其适用于对数据完整性和准确性要求较高的场景。
- Nagle 算法设置:为了降低延迟并提高反应速度,在使用 TCP 绑定进行 SOME/IP 通信时,应关闭 Nagle 算法(即设置 TCP_NODELAY 选项)。Nagle 算法的目的是减少网络中微小数据包的数量,但在某些实时性要求较高的场景下,关闭它可以使消息能够更快地发送出去,减少不必要的等待时间。
- 连接管理责任与行为
- 连接建立与关闭时机:TCP 连接由客户端负责管理。当客户端需要发送第一个方法调用或者尝试接收第一个通知时,它会主动打开 TCP 连接;当 TCP 连接不再需要时(例如,相关服务已停止或超时),客户端负责关闭连接。这确保了连接的有效性和资源的合理利用,避免不必要的连接占用网络资源和系统开销。
- 连接丢失处理:如果 TCP 连接丢失,客户端未完成的请求将被视为超时。这意味着客户端需要在应用层处理这种超时情况,可能需要采取相应的措施,如重新发送请求或者进行错误处理,以保证业务逻辑的正确性。
- 多服务实例与连接关系:对于一个服务实例的所有方法、事件和通知,都使用单个 TCP 连接进行传输,以保证数据的有序性和连贯性。当存在多个服务实例时,每个服务实例需要单独的 TCP 连接,这样可以避免不同服务实例之间的通信干扰,确保每个服务实例的通信独立、稳定。
- 魔数饼干(Magic Cookies)的作用:为了便于测试工具识别通过 TCP 传输的 SOME/IP 消息边界,可在 TCP 消息流中定期插入 SOME/IP 魔数饼干消息。这些魔数饼干消息具有特定的格式和内容,就像在消息流中设置的特殊标记,测试工具可以通过检测这些标记来准确地确定 SOME/IP 消息的起始和结束位置,从而更好地进行测试和分析工作。
1.3 多服务实例
- 实例区分方式:同一服务的不同实例通过唯一的实例 ID 进行区分。这个实例 ID 在服务发现和通信过程中起到关键作用,使得系统能够准确识别和定位不同的服务实例,就像每个人都有唯一的身份证号码一样,用于在众多服务实例中准确找到目标实例。
- 部署情况与端口分配:这些服务实例可以分布在不同的电子控制单元(ECU)上,也可以多个实例同时存在于一个 ECU 中。在端口分配方面,不同的服务可以共享传输层协议(如 UDP 或 TCP)的相同端口号,但同一服务的不同实例在单个 ECU 上必须监听不同的端口。这样的设计确保了在复杂的汽车电子系统中,不同服务实例之间的通信不会发生冲突,并且能够被准确地路由和处理。例如,多个不同的服务可以共同使用 UDP 的 5000 端口进行通信,但如果一个服务有多个实例在同一 ECU 上运行,每个实例将使用不同的端口,如 5001、5002 等,通过服务 ID、实例 ID 以及端口号的组合,系统能够精确地找到目标服务实例进行通信。
1.4 通过 UDP 传输大型 SOME/IP 消息(SOME/IP - TP)
- 协议应用场景与消息分割:当需要通过 UDP 传输大于 1400 字节(UDP 有效载荷的典型限制)的 SOME/IP 消息时,SOME/IP - TP 协议就发挥作用了。它将原始的大型 SOME/IP 消息分割成多个较小的片段(称为段)进行传输,每个段都能够适配 UDP 的传输限制,就像把一个大包裹拆分成几个小包裹以便于运输。
- TP 头部结构与功能:每个 SOME/IP - TP 段在 SOME/IP 头部之后紧接着包含一个 TP 头部。TP 头部包含了多个重要字段,如 28 位的偏移字段,用于指示该段在原始消息中的位置偏移量(以 16 字节为单位);3 个 1 位的保留标志字段,发送方设置为 0,接收方忽略;1 位的更多段标志字段,用于标识当前段是否为最后一个段,除最后一段外,其他段该标志位都设置为 1。这些字段共同协作,为接收方提供了重组原始消息所需的关键信息,使得接收方能够准确地将各个段还原为原始的大型消息。
- 发送方行为规则
- 分段决策依据:发送方仅对配置为可分段的消息进行分段操作,这是根据系统或应用的配置来确定的,确保只有需要分段的大型消息才会被处理,避免不必要的资源消耗。
- 段顺序与大小优化:发送方按照顺序发送段,并且在满足协议规范限制的前提下,尽量最大化每个段的大小。所有设置了更多段标志为 1 的段(即非最后一段)应具有相同的大小,这样可以简化接收方的重组过程,提高重组效率,同时也有助于合理利用网络资源。发送方不能发送重叠或重复的段,以保证消息的准确性和完整性,避免在接收方重组时出现混淆或错误。
- 接收方行为规则
- 消息重组依据:接收方根据消息的配置值(如消息 ID、协议版本、接口版本和消息类型(不含 TP 标志))来匹配用于重组的段,确保不同的消息不会被错误地组合在一起。通过这些关键信息,接收方能够从接收到的众多段中准确筛选出属于同一原始消息的段,并按照正确的顺序进行重组。
- 会话 ID 的作用:会话 ID 在重组过程中起到了重要的作用,它用于检测下一个需要重组的原始消息,以及处理乱序到达的段。当接收方收到一个具有不同会话 ID 的新段时,会启动新的重组过程,并可能丢弃之前未成功重组的旧段,确保每个会话内的消息重组独立、准确。
- 资源限制与处理:接收方应在其配置的有限资源范围内进行重组操作,特别是缓冲区大小的限制。如果重组后的消息达到缓冲区大小限制,接收方应停止重组并跳过剩余部分,仅将正确重组且大小在配置范围内的消息传递给应用程序,防止因消息过大导致缓冲区溢出等问题,保证系统的稳定性和可靠性。
- 错误处理与容忍度:接收方能够处理各种异常情况,如段的重排序(支持一定的重排序距离,至少 3 个位置的乱序)、重叠和重复段(通过覆盖等方式正确重组)。如果检测到明显错误(如段长度不符合要求),接收方应能够优雅地处理,例如取消重组操作,以避免错误数据的传播和影响应用程序的正常运行。同时,接收方不支持不同原始消息的段在同一缓冲区中交错处理,确保每个消息的处理独立、有序,防止数据混乱。
2. 请求 / 响应通信
2.1 客户端请求消息构造
- 有效载荷构建:客户端在发送请求消息时,首先要根据具体的业务需求构造有效的载荷。这个有效载荷包含了方法调用所需的参数等信息,是服务器执行操作的关键数据来源,就像给服务器传递的任务清单,详细列出了需要完成的任务内容。
- 头部字段设置
- 消息 ID 确定:根据客户端想要调用的方法来设置消息 ID,这个消息 ID 在整个系统中必须是唯一的,类似于给每个请求贴上一个独特的标签,用于在服务器端准确识别请求对应的方法,确保请求能够被正确路由和处理。
- 长度字段计算:长度字段设置为 8 字节(表示 SOME/IP 头部中消息 ID、请求 ID 等部分之后的长度)加上序列化后的有效载荷长度。这使得接收方能够准确知道整个请求消息的大小,从而正确地接收和处理消息,避免因长度信息不准确导致的接收错误或数据丢失。
- 请求 ID 赋值(可选):客户端可以选择为请求 ID 设置一个唯一的数字,这个请求 ID 在客户端范围内是唯一的,用于区分不同的请求,特别是在处理并发请求时,服务器可以通过请求 ID 将响应准确地对应到相应的请求,就像给每个请求一个排队号码,以便在处理完成后能准确地将结果返回给对应的请求者。
- 协议版本指定:按照 [PRS_SOMEIP_00052] 的规定设置协议版本,确保客户端和服务器在协议理解上的一致性,避免因协议版本不匹配导致的通信问题,就像双方使用相同的语言进行交流,保证信息能够准确传达和理解。
- 接口版本设置:根据接口定义设置接口版本,这对于确保客户端和服务器之间接口的兼容性至关重要,不同版本的接口可能在参数格式、数据类型等方面存在差异,正确设置接口版本可以保证请求能够在服务器端正确解析和处理。
- 消息类型设定:将消息类型设置为 REQUEST(0x00),明确告知服务器这是一个需要响应的请求消息,服务器收到后会根据这个类型进行相应的处理流程,就像在请求上标明 “需要回复” 的标记,让服务器知道如何处理这个消息。
-返回码初始化:将返回码设置为 0x00(E_OK),表示初始状态下请求未发生错误,这个返回码在请求发送时只是一个初始占位符,服务器在处理请求后会根据实际情况更新返回码,用于向客户端反馈请求的处理结果。
2.2 服务器响应消息构建
- 响应消息构造流程:服务器在接收到客户端的请求消息后,根据客户端请求的头部信息构建响应消息的头部。首先,服务器会接管客户端请求中的消息 ID,确保响应消息与请求消息的对应关系,就像在回复信件时保留原信件的主题,使双方能够清楚地知道这是针对哪个请求的回复。
- 头部字段更新与设置
- 长度调整:服务器将长度字段设置为 8 字节加上新构建的有效载荷大小,准确反映响应消息的整体长度,包括头部和有效载荷部分,以便客户端能够正确接收和解析响应消息,避免因长度信息错误导致接收异常。
- 请求 ID 沿用:直接沿用客户端请求中的请求 ID,这使得客户端能够通过请求 ID 将接收到的响应准确地与之前发送的请求进行匹配,就像在回复中引用原请求的排队号码,确保响应能够准确地找到对应的请求者。
- 消息类型确定:根据请求的处理结果,将消息类型设置为 RESPONSE(0x80)表示成功处理并返回结果,或者设置为 ERROR(0x81)表示处理过程中发生错误。这样客户端在收到响应时,通过消息类型就能快速判断请求的处理状态,就像在回复中注明 “成功” 或 “失败”,让请求者第一时间了解结果。
- 返回码设置:将返回码设置为被调用方法的返回码,或者在错误消息的情况下,设置为有效的错误码(如 [PRS_SOMEIP_00191] 中定义的错误码)。这个返回码是服务器向客户端反馈请求处理详细结果的重要信息,客户端可以根据返回码进行相应的处理,如显示错误信息给用户或进行进一步的错误恢复操作。
- 有效载荷构建依据:服务器根据被调用方法的签名中参数的顺序,将所有输出或输入 / 输出参数序列化后构建有效载荷。这确保了响应消息中的数据与方法执行的结果准确对应,并且按照客户端能够理解的顺序进行组织,就像按照任务清单的格式填写任务完成后的结果,使客户端能够正确解析和使用这些数据。
2.3 请求 / 响应交互规则
- 服务器响应时机限制:服务器必须在接收到对应的请求消息后,才能发送响应消息。这保证了响应的准确性和有效性,避免发送无意义或错误的响应,就像只有在收到问题后才能给出正确的答案,确保通信的逻辑性和正确性。
- 客户端响应接收处理:客户端在发送请求消息后,会等待接收响应消息。如果在请求消息尚未完全发送出去时就接收到了响应消息,客户端应忽略该响应消息,因为这可能是由于网络延迟或其他异常情况导致的错误响应,确保客户端只处理与完整发送的请求对应的有效响应。
3. Fire&Forget 通信
3.1 消息构造特点
- 无响应特性体现:Fire&Forget 通信模式下,客户端发送的请求消息不需要服务器返回响应。这种通信方式适用于一些对实时性要求较高,但对响应结果不敏感的场景,例如发送一些状态更新或日志信息,客户端只关心消息是否成功发送,而不需要等待服务器的反馈。
- 头部字段设置要求
- 消息 ID 与有效载荷构建:与请求 / 响应通信类似,客户端根据想要调用的方法设置消息 ID,并构造有效的载荷,其中包含了相关的信息或数据。虽然没有响应,但有效载荷的内容仍然需要准确传达所需的信息,就像投递一封不需要回信的信件,但信件内容必须清晰明确。
- 长度字段计算:长度字段同样设置为 8 字节(表示 SOME/IP 头部部分之后的长度)加上序列化后的有效载荷长度,确保接收方能够正确识别消息的边界,即使没有响应,消息的完整性和格式正确性仍然重要,以便接收方能够正确处理接收到的消息。
- 请求 ID 赋值(可选):客户端可以为请求 ID 设置一个唯一的数字(在客户端范围内唯一),用于在需要时区分不同的 Fire&Forget 请求,尽管没有响应关联,但在客户端自身的请求管理和日志记录等方面可能会用到这个请求 ID,就像给每个不需要回复的任务一个内部编号,方便自己管理和追溯。
- 协议版本与接口版本设置:按照规定设置协议版本和接口版本,保证与服务器端的兼容性,即使没有响应交互,双方在协议和接口理解上的一致性仍然是确保消息能够被正确接收和处理的基础,避免因版本不匹配导致的通信问题。
- 消息类型设定:将消息类型设置为 REQUEST_NO_RETURN(0x01),明确告知接收方这是一个 Fire&Forget 类型的请求,接收方(通常是服务器或其他接收组件)在收到这样的消息后,知道不需要发送响应,从而按照相应的处理逻辑进行处理,就像在信件上标明 “无需回复”,让接收者知道如何处理该信件。
- 返回码初始化:将返回码设置为 0x00(E_OK),表示请求在发送时的初始状态为正常,尽管不会有实际的返回码反馈,但这个初始值在消息格式上保持了一致性,并且在一些可能的内部处理或日志记录中可以表示请求的初始发送状态。
3.2 错误处理责任
- 应用层处理机制:由于 Fire&Forget 通信没有服务器返回的响应消息来传递错误信息,所以错误处理主要由应用程序来承担。当应用程序认为需要处理可能发生的错误情况时,它需要自行实现相应的错误检测和处理逻辑。例如,在发送 Fire&Forget 消息后,应用程序可以通过其他方式(如检查本地日志、网络状态监测等)来判断消息是否成功发送,如果发现可能存在问题(如网络中断导致消息发送失败),应用程序可以采取一些措施,如重新发送消息、记录错误信息以便后续分析等,这就要求应用程序开发者在设计时充分考虑到这些情况,并编写相应的代码来处理可能出现的错误,以确保系统在这种通信模式下的可靠性和稳定性。
4. 通知事件
4.1 服务器通知消息构造
- 有效载荷与消息 ID 设置:服务器构造通知消息时,有效载荷包含了如车辆传感器数据更新、系统状态变更等具体信息,这些信息是客户端需要知晓的内容。消息 ID 的设置如同给每个通知贴上独特标签,比如在车辆监控系统里,车门状态变化的通知和发动机故障的通知会有不同的消息 ID,以便客户端区分处理。
- 头部字段设置规则
- 长度字段计算:长度字段涵盖 8 字节基本头部信息及序列化后有效载荷长度。以车辆速度更新通知为例,若速度数据序列化后长度为 20 字节,加上 8 字节头部,长度字段就设为 28 字节,确保客户端能准确接收完整通知。
- 客户端 ID 与会话 ID 处理:客户端 ID 设为 0x00,因为通知面向多个订阅客户端,不针对单个。会话 ID 在活动会话处理时,如车辆远程诊断场景,每次传输递增,方便区分不同诊断会话;未激活时设为 0x00。
- 协议版本与接口版本设置:协议版本按规定设置,如车辆系统都遵循统一的 SOME/IP 协议版本,确保通信无误。接口版本依接口定义而定,不同车辆功能模块(如娱乐系统和安全系统)接口版本可能不同,需准确设置保证兼容性。
- 消息类型设定:设为 NOTIFICATION(0x02),客户端收到便知是服务器主动推送的事件通知,如车辆导航系统收到路况更新通知,就按此类型处理逻辑更新地图显示。
- 返回码初始化:设为 0x00(E_OK),表示初始正常,在车辆数据采集系统中,若通知发送时无问题则为该值,后续若采集设备故障等可更改返回码。
4.2 通知消息的发送策略
- 周期性更新:车辆仪表盘每秒获取一次车速传感器数据,服务器周期性发送车速更新通知,保证仪表盘实时显示准确车速,让驾驶员随时掌握车辆速度。
- 值改变时更新:车辆门锁状态改变时,无论是从开到关还是反之,服务器立即发送通知,使车内状态显示系统及时更新,让乘客知晓车门状态。
- 基于阈值变化更新(Epsilon 变化):车辆电池电量监测,当电量变化超过设定的 2% 阈值,或者与基于历史数据预测的电量值相差超阈值,服务器发送通知,避免频繁通知,又确保车主关注到电量显著变化。
5. 字段
- 字段的组成与功能特性:在车辆控制系统里,一个表示车辆灯光状态的字段,其 getter 可让仪表盘获取当前灯光是开还是关;setter 能让驾驶员通过控制开关向服务器发送改变灯光状态请求;若灯光因故障等原因状态改变,服务器通过通知事件告知仪表盘更新显示,字段至少具备这些功能中的一个。
- 字段在系统中的作用与交互方式:以车辆发动机转速字段为例,发动机控制单元是服务器,仪表盘是客户端。仪表盘通过 getter 获取转速值显示;驾驶员操作加速踏板,仪表盘通过 setter 向发动机控制单元发送调整转速请求;发动机转速因运行状态变化时,发动机控制单元通过通知事件通知仪表盘更新,实现信息实时同步。
6. 错误处理
6.1 返回码
- 返回码的作用与数据类型:在车辆远程控制场景中,返回码就像遥控器操作车辆后的反馈信号。它是 8 位无符号整数,如控制车辆车窗升降,服务器返回码告知客户端操作是否成功及原因,帮助客户端判断并处理。
- 返回码的定义与取值范围:比如 0x00(E_OK)表示成功升降车窗;0x04(E_NOT_READY)可能是车窗电机未就绪;0x05(E_NOT_REACHABLE)可能是车辆网络通信故障无法控制车窗。不同返回码让客户端明确操作结果,对车辆系统状态做出正确反应。
- 返回码的配置与处理规则:在车辆诊断系统中,可配置返回码生成方式。如对某些轻微故障,可选择不返回详细码,或转换为通用码处理。同时,客户端根据应用程序逻辑解读,如收到非 0x00 返回码,结合业务决定是否重试操作或提示用户。
6.2 错误消息
- 错误消息的作用与布局特点:车辆系统中,错误消息像详细的故障报告。特殊布局中的异常联合和动态长度字符串,如发动机控制系统报错,联合中的特定异常类型指出故障类型(如燃油喷射故障),字符串描述具体错误(如喷油嘴堵塞),方便维修人员定位问题。
- 错误消息的发送与处理规则:当车辆安全系统检测到关键传感器故障,服务器构造错误消息发送给监控中心客户端。客户端收到后,根据联合和字符串信息记录日志、通知维修人员,对事件 / 通知和 Fire&Forget 方法,遵循不返回错误消息规则,避免不必要通信。
6.3 错误处理概述
- 错误处理的依据与流程:车辆网络通信中,收到消息先判断类型。若是车辆控制指令消息,检查指令合法性、参数范围;若是响应消息,检查返回码和数据匹配性。整个过程按定义顺序检查,保证错误处理有序。
- UDP 与 TCP 传输的错误检查差异:在车辆自组网(UDP 传输)场景下,接收消息检查 UDP 数据报大小和长度字段,防止因网络不稳定导致格式错误消息影响系统。而在车辆远程信息处理(TCP 传输)中,若出错检查连接状态,如发送魔数饼干消息确认连接,必要时重连,确保可靠通信。
6.4 通信错误及处理
- 可靠性语义与通信错误类型:在车辆远程升级场景中,若采用 UDP 传输升级包,可能因网络差出现 “maybe” 可靠性问题,如升级包丢失、乱序或重复。而 TCP 传输可保证 “exactly once” 可靠性,但也可能面临网络拥塞导致传输延迟。
- UDP 与 TCP 的可靠性实现及应用处理:UDP 传输升级包时,客户端设置超时,若超时未收到响应,提示用户升级失败,用户可重试。TCP 传输时,应用层处理如显示升级进度、处理服务器返回的应用错误码,确保升级过程顺利和系统稳定。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/891062.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!