在之前的文章中,我们介绍了SOME/IP协议的几种服务接口。在本篇博客中,主要介绍some/ip协议传输的header报文格式以及SOME/IP-SD发现协议。
目录
流程
报文格式
Message ID
Length
Request ID
protocal version/Interface Version
Message Type
Return Code
SOME/IP-SD
什么是SOME/IP-SD?
SD 消息类型解析
订阅相关
例子
SOME/IP-SD如何实现服务发现
分类
Find(查找服务)
Offer(服务器提供服务信息)
关键概念
工作流程
Eventgroup
Method
流程
SOME/IP协议主要工作如果在TCP/IP模型下处于应用层,而在OSI7层模型中他的序列化反序列化处于表示层,RPC处于会话层。因为表示层处理加密解密/压缩解压缩,会话层管理建立和终止通信。具体来说就是SOME/IP协议先给数据加一个协议头部再交给传输层。如果有三台设备连接在switch上,任何设备想将数据发送给其他设备,都需要将数据发送给switch(交换机)中转,然后由switch发送给其他设备。如果直接发送源消息,switch并不知道要发送给谁,因此有了报文封装。每层往下依次添加协议头.
报文格式
这是AP AUTOSAR文档中《SOME/IP Protocol Specification.pdf》中的一段SOME/IP报文格式。我们可以看到他有16字节的大小。
Message ID
Message ID占4字节,其中method id和service id分别占两字节,在之前的服务接口我们有提到,首先不同的服务有不同的service id.service ID往下则分为组ID,method 也有不同的ID。那么some/ip报文前4个字节就是用来确定服务和使用哪种功能的。这里需要注意的是event id 保存在method Id 字段 当someip消息类型是event时候,那么method id保存的是event id。有些朋友可能会疑惑,我们知道method就一个ID但是组有组ID和对应的事件ID也就是2个,这个method字段放得下吗?需要解答这个问题首先我们要知道我们只需要订阅一个组,所有的event就都会向你推送消息。some/ip不能想ros或者dds那样单独订阅一个话题。event id用于服务端管理和识别不同的事件而,对客户端来说没什么用。但是我怎么知道是event id还是method id呢?这里给出解答,可以通过 method id进行区分。大于0x8000的是event,小于的是method。
Length
他和IP协议16位总长度不太一样,它并不表示报文头+负载数据二十,表示request id 到后面负载结束的长度,接收方可以通过Length知道是否已经完整接收到消息。也就是说他上面8字节的长度是不包含在内的。
Request ID
Request ID由Client ID和Session ID组成,各占两个字节。Client ID用于区分使用同一method的不同客户端,相当于mac地址,也就是身份证号,不然他不知道给谁。不同的客户想使用相同服务ID的同一个Method怎么进行区分呢,一般来说是使用端口+ip地址进行区分,但是很遗憾vsomeip并不支持端口与Ip地址。在respond和request中,client的ID都是一样的,这样能知道返回的客户是谁,seesion ID,数据的发送方每发送一次数据,这个ID就加1,他从0x1加到 0xffff满了之后又从0x1开始加。因此session ID可以帮助我们区分每一条消息,每个消息的session ID都不一样。Request seesion id 为1000 代表这是客户端发送的第1000次请求消息。同时respond的seesion ID也是和request一样的,这样可以让我们知道服务端是在响应客户端的哪一次请求。
protocal version/Interface Version
这俩一般请求和响应的头都是一样的,毕竟只有协议版本接口版本一致,才能完成通信。在vsomeip中,接口版本是1 在someip中接口版本默认是0。
Message Type
前面留了个疑问,如何分辨event消息还是method 消息?这里给出解答,可以通过 method id进行区分。大于0x8000的是event,小于的是method。那么我们怎么知道method消息,是服务端发送的reponse还是客户端发送的request?这时候method id是一致的,那我们就可以通过Message Type字段来进行判断了。0x00是 RR,0x01是FF,event是0x02.
Return Code
当服务端不能正确处理request消息,那么他的原因就会存储在return code中.
数值 (8-bit) | 报文类型 (Message Type) | 描述 | 适用场景 |
---|---|---|---|
0x00 | REQUEST | 请求消息,客户端向服务器发送请求,并期望得到响应 (RESPONSE ) | 远程方法调用(RPC),如“获取 ECU 状态” |
0x00 | REQUEST_NO_RETURN | 无返回请求,客户端向服务器发送请求,但不需要响应 | 发送一次性控制指令,如“打开车灯” |
0x00 | NOTIFICATION | 通知消息,服务器主动推送数据,客户端不需要请求 | 事件通知(Event),如“发动机温度变化” |
0x00 | RESPONSE | 响应消息,服务器对 REQUEST 请求的回应 | 服务器返回请求结果,如“当前车速” |
具体值 | ERROR | 错误消息,表示 REQUEST 失败,并包含错误码(Return Code) | 服务不可用、超时、协议错误等 |
错误码(数值) | 错误类型 | 含义 | 描述 |
---|---|---|---|
0x00 | E_OK | 无错误 | 请求成功执行 |
0x01 | E_NOT_OK | 未知错误 | 服务器无法识别的错误 |
0x02 | E_UNKNOWN_SERVICE | 未知 Service ID | 请求的服务 ID 不存在 |
0x03 | E_UNKNOWN_METHOD | 未知 Method ID | 请求的方法 ID 不存在 |
0x04 | E_NOT_READY | 应用未就绪 | 服务器上的应用程序未运行 |
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 | 报文类型错误 | 收到了无效的报文类型 |
SOME/IP-SD
就像DDS一样,SOME/IP也有自己的发现机制。不过DDS是每个节点都能自己发现,而someip遵循SOA思想,服务发现机制位于服务中心里,订阅消息回应ack与 停止订阅消息都属于sd不属于someip.
协议 | 发现机制 | 发现方式 | 中心化 vs. 去中心化 |
---|---|---|---|
DDS(Data Distribution Service) | 内置发现机制(自动发现) | 每个 DDS 节点(DomainParticipant)都会广播并自动发现其他节点 | 去中心化(Decentralized) |
SOME/IP(Scalable service-Oriented Middleware over IP) | 服务发现(Service Discovery,SD) | 客户端-服务器模式,服务中心管理注册和发现 | 中心化(Centralized) |
什么是SOME/IP-SD?
- 本质:SOME/IP-SD 是 SOME/IP 的服务发现机制,可以理解为一种特殊的服务,用于动态管理和发现网络中的服务。
- 功能:
- 定位服务(Service Discovery):客户端寻找某个服务,服务器响应并告知 IP/端口。
- 订阅(Subscription):客户端订阅事件组(Eventgroup),服务端确认或拒绝。
SD 消息类型解析
SOME/IP-SD 的消息分为 两大类:
-
服务发现相关(Service Discovery)
FindService
:客户端查找服务(广播/多播)。(client)OfferService
:服务器响应,提供服务 IP 和端口。(server)StopOfferService
:服务器通知停止提供某个服务。(server)
-
订阅相关(Event Subscription)
SubscribeEventgroup
:客户端请求订阅某个事件组。(client)SubscribeEventgroupACK
:服务器确认订阅成功。(server)SubscribeEventgroupNACK
:服务器拒绝订阅请求。(server)StopSubscribeEventgroup
:客户端取消订阅事件组。(client)
SD就是靠这7种不同的消息实现,server和client都有自己的独有消息,只有自己可以发送.客户端可以通过发送FindService消息来查找自己感兴趣的服务,服务端可以根据offerservice消息通知客户端,自己可以提供哪些服务。并且通过offerservice消息将他的ip传输层协议端口这些通信必要信息告知给客户端。服务端可以根据StopOfferServiced来告诉客户端他不再提供某些服务,比如要升级服务端消息,就先停止再发送
订阅相关
客户端可以向服务端发送SubscribeEventgroup来订阅某个事件组,同时也告诉服务端自身的Ip端口通信协议并且会携带客户端感兴趣的service id和eventgroup id.服务端可以根据实际情况发送ack 订阅事件组ack消息,来告诉客户端已经成功订阅事件组。或者另一个来告诉客户端订阅失败
例子
客户端发送0x1234的消息来查找可以提供0x1234服务的客户端,你们谁提供。可以提工单就发送offer,根据通过service消息将他的ip传输层协议端口这些通信必要信息告知给客户端。
SOME/IP-SD如何实现服务发现
想想这样一个场景有5台设备连接了交换机,那么他能进行单播(一对一直接发),广播(255.255.255.255),组播(239.0.0.0~239.,255.255.255),some/ip默认是224.244.224.245,默认端口是30490。正如我们之间传输层讲解的那样,单播:比如这里的设备1发出的消息只有设备5能够收到,广播是一对多的关系,广播将发送方的消传递给局域网内的所有接收端。组播:与广播不同的是,只有特定条件的客户端可以收到消息他是以ip来对组播组进行划分 比如224.1.3.1就是一个组。
分类
在 SOME/IP-SD(Service Discovery) 中,服务发现的流程包括:
- Find(客户端查找服务)
- Offer(服务器提供服务信息)
Find(查找服务)
- 触发条件:当 客户端(Client)启动 时,它需要找到某个 服务(Service),例如
0x1234
。 - 查找方式:
- 组播(Multicast)方式:客户端通过 UDP 组播 发送
FindService
消息,查询 "谁提供0x1234
服务?"。 - 客户端会发送
n
条Find
消息,以确保所有服务器都能收到请求。
- 组播(Multicast)方式:客户端通过 UDP 组播 发送
📌 解析(Find 阶段):
Client
启动后,向局域网内的所有服务器广播FindService
(橙色箭头)。- 这个过程是**“快速对外发送”**,客户端会连续发送多条
Find
消息,确保覆盖整个网络。
Offer(服务器提供服务信息)
服务器在收到 FindService
消息后,会通过 OfferService 进行响应,该过程分为两个阶段:
-
阶段 1(Server 启动后主动广播 Offer 消息)
服务器启动后,会周期性以组播(Multicast)方式发送n条OfferService
,告诉网络中的设备:"我提供0x1234
服务,我的 IP 是192.x.x.x
,端口是55001
。"
阶段 2(周期性发送Offer 消息)
这保证即使客户端晚一些启动,也能发现这个服务。
- 阶段 3(Server 收到 Find 后,单播 Offer 消息)
- 如果服务器收到了
FindService
请求,它会直接单播(Unicast)OfferService
给该客户端,告诉它服务可用,并提供IP 和端口信息。
- 如果服务器收到了
关键概念
阶段 | 角色 | 通信方式 | 描述 |
---|---|---|---|
Find | Client | UDP 组播(Multicast) | 客户端查找 FindService ,广播请求 |
Offer(阶段1) | Server | UDP 组播(Multicast) | 服务器启动时主动广播 OfferService |
Offer(阶段2) | Server | UDP 单播(Unicast) | 服务器收到 FindService 请求后,直接单播 OfferService 给客户端 |
为什么find和offer消息是以组播形式传播的?是因为他不知道系统中谁能提供自己感兴趣的服务,使用组播而不使用广播是因为可以避免其他没有使用someip协议的接收到消息,为什么要发送多条消息?是因为定位使用的是upd协议,不可靠,为什么要分为两个阶段先快速发送offer消息然后再周期性发送消息?第一时间的快速发送消息就是为了让客户端能第一时间接收到服务端的offer消息,而第二阶段的存在是为了避免浪费网络带宽如果服务端收到了find消息,服务端就会以单播形式发送给客户端,有了周期性发送offer为什么还要单播呢?这是因为周期性发送offer消息的时间间隔过长,让客户端第一时间接受offer消息.
工作流程
Eventgroup
client发送FindService报文,server发送offerService报文。之后客户端才能发订阅某个方法啊,订阅的时候发具体订阅某哪个事件组.server会回一个同意或者不同意的ack,之后就正常推送event事件。不需要了就发一个停止订阅组。
Method
如果客户端不知道服务端的ip&&port。那么就需要通过发现协议先知道Ip和端口,然后就可以直接调用rpc了,不需要发什么请求订阅消息组之类的。直接调用,请求消息头部的Message ID和Message Type会告诉server是Method请求还是请求订阅事件组。如果是RPC会直接调用方法。