写在开篇·蓉儿继续挖坑
上回说到,郭靖搞清楚了Find Service------客户端主动问"谁会啥",服务端单播回复。
郭靖合上笔记本,信心满满:"蓉儿,我懂了!Offer是服务端喊'我在这',Find是客户端问'谁在'。双保险,总能找到服务。"
黄蓉咬了口糖葫芦:"那好,我问你------服务找到了,地址也知道了。那车窗位置变化时,车窗怎么主动告诉座舱?"
郭靖一愣:"用Event?之前讲过。"
黄蓉:"对,Event。但客户端怎么告诉服务端'我想收这个Event'?服务端怎么知道要推给谁?"
郭靖摇头。
"这就是Subscribe的用武之地。想收通知要订阅,订阅之后随心阅。 今天就把Subscribe讲透。"
一、Subscribe是什么
黄蓉在白板上写下定义:
Subscribe = 客户端主动告诉服务端"我想订阅某个EventGroup,有通知请推给我"
| 角色 | 动作 | 说明 |
|---|---|---|
| 客户端(如座舱) | 发送Subscribe | "我想收EventGroup 0x1001的通知,请把我加进推送列表" |
| 服务端(如车窗ECU) | 回复SubscribeACK | "订阅成功,以后有通知就推给你" |
"Subscribe是客户端的'订阅请求'。 你不订阅,服务端不知道要把通知推给谁。"
二、为什么要订阅?Event不能直接广播吗?
郭靖问:"Event不能像Offer一样广播吗?谁想听谁听。"
黄蓉摇头:"Event如果广播,所有ECU都会收到,不管想不想听。 车上几十个ECU,每个ECU都广播自己的Event,网络会被淹没。"
| 方式 | 说明 | 网络负载 |
|---|---|---|
| 广播Event | 所有Event发给所有人 | 高(N个服务 × M个客户端 = N×M条消息) |
| 订阅+单播 | 只推给订阅了的客户端 | 低(N个服务 × 订阅数) |
"订阅机制的精髓:按需推送,谁订阅给谁。订阅之后更便捷------不用轮询,不用广播轰炸。"
三、EventGroup是什么(复习+深化)
黄蓉在白板上画了EventGroup的结构:
┌─────────────────────────────────────────────────────────────────────┐
│ 车窗服务的EventGroup │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ EventGroup 0x1001(位置相关事件组) │
│ ├── Field Notifier:车窗位置变化(0x8002) │
│ ├── Event:车窗防夹触发(0x8003) │
│ └── Event:车窗到位通知(0x8004) │
│ │
│ EventGroup 0x1002(故障相关事件组) │
│ ├── Event:电机过载(0x8010) │
│ └── Event:霍尔传感器故障(0x8011) │
│ │
└─────────────────────────────────────────────────────────────────────┘
"EventGroup是一组相关Event/Notifier的集合。 订阅EventGroup,就一次性订阅了里面所有Event。"
郭靖:"那为什么不一个Event订阅一次?"
黄蓉反问:"你要收位置变化、防夹、到位三个通知,你是想发3次订阅请求,还是发1次?"
"1次......"
"对!EventGroup就是为了减少订阅请求数量。"
四、一个完整的Subscribe报文示例
黄蓉调出一个座舱订阅EventGroup 0x1001的完整报文(按字段分组):
FF FF | 81 00 | 00 00 00 18 | 12 34 | 00 08 | 01 | 01 | 02 | 00 | 01 | 01 | 00 00 | 00 0C | 03 00 | 00 01 | 10 01 | 00 00 00 00
第一步:SOME/IP头部(12字节)
| 分组 | 值 | 说明 |
|---|---|---|
| Service ID | FF FF |
SD专用固定ID |
| Method ID | 81 00 |
SD专用固定Method ID |
| Length | 00 00 00 18 |
24字节 |
| Client ID | 12 34 |
座舱的ID |
| Session ID | 00 08 |
第8次请求 |
| Message Type | 02 |
NOTIFICATION |
"还是SD消息,FF FF 81 00。"
第二步:SD头部(4字节)
| 分组 | 值 | 说明 |
|---|---|---|
| Version | 01 |
SD版本1 |
| Message Type | 03 |
Subscribe(Offer=02,Find=01,Subscribe=03) |
| Reserved | 00 00 |
保留 |
| Entry Count | 00 00 00 01 |
有1个Entry |
第三步:Subscribe Entry
| 分组 | 值 | 说明 |
|---|---|---|
| Entry Type | 00 06 |
Subscribe |
| Length | 00 0C |
12字节 |
| Service ID | 03 00 |
要订阅的车窗服务 |
| Instance ID | 00 01 |
左前窗实例 |
| EventGroup ID | 10 01 |
订阅的EventGroup |
| TTL | 00 00 00 00 |
0表示"永久订阅"(直到退订) |
五、服务端收到Subscribe后做什么
黄蓉画了车窗ECU收到Subscribe后的处理流程:
车窗ECU收到Subscribe报文:
│
├── 解析出:Service ID=0x0300,Instance ID=0x0001,EventGroup=0x1001
│
├── 检查自己有没有这个EventGroup → 有!
│
├── 把座舱(Client ID=0x1234)加入推送列表
│
├── 回复SubscribeACK
│
└── 之后,EventGroup 0x1001里的任何Event/Notifier发生,都推给座舱
SubscribeACK报文:
FF FF | 81 00 | 00 00 00 10 | 12 34 | 00 08 | 01 | 01 | 02 | 00 | 01 | 01 | 00 00 | 00 04 | 00 06 | 00 00
六、订阅后的推送流程
黄蓉画了完整的订阅+推送时序图:
座舱(客户端) 车窗ECU(服务端)
│ │
│ ① Subscribe(订阅EventGroup 0x1001) │
│──────────────────────────────────────────>│
│ │
│ ② SubscribeACK(订阅成功) │
│<──────────────────────────────────────────│
│ │
│ │ ③ 车窗位置从50%升到80%
│ │
│ ④ Notifier(位置变化,0x8002,80%) │
│<──────────────────────────────────────────│
│ │
│ │ ⑤ 车窗防夹触发
│ │
│ ⑥ Event(防夹触发,0x8003) │
│<──────────────────────────────────────────│
"订阅一次,收到所有推送。订阅之后更便捷------不用轮询,不用每次都问。"
七、退订:Unsubscribe
郭靖问:"那如果座舱不想收通知了怎么办?"
黄蓉:"Unsubscribe------退订。"
| 操作 | Entry Type | 说明 |
|---|---|---|
| Subscribe | 0x0006 |
订阅 |
| SubscribeACK | 0x0007 |
订阅确认 |
| Unsubscribe | 0x0006 + TTL=0 |
退订(特殊标记) |
"Unsubscribe报文和Subscribe结构一样,TTL=0表示'我要退订'。"
八、Subscribe vs Find vs Offer 对比
黄蓉画了一张完整对比表:
| 对比项 | Offer | Find | Subscribe |
|---|---|---|---|
| 谁发起 | 服务端 | 客户端 | 客户端 |
| 目的 | 告知"我会啥" | 询问"谁会啥" | 订阅"我想收通知" |
| 发送方式 | 广播 | 广播 | 单播(通常) |
| 响应 | 无 | 单播Offer | 单播SubscribeACK |
| Entry Type | 0x0001 |
0x0000 |
0x0006 |
| SD Message Type | 02 |
01 |
03 |
九、SD三驾马车总结
黄蓉在白板上写下了SD的三个核心功能:
| 功能 | 一句话 | 状态 |
|---|---|---|
| Offer | 服务端喊"我会啥" | ✅ 已学 |
| Find | 客户端问"谁会啥" | ✅ 已学 |
| Subscribe | 客户端订"我想收" | ✅ 刚学 |
"三驾马车齐了。Offer让客户端知道服务在哪,Find让客户端主动找服务,Subscribe让客户端收通知。"
十、黄蓉的小本本
郭靖翻开她的笔记本,上面写着:
Subscribe核心要点:
1. 客户端主动订阅:告诉服务端"我想收这个EventGroup的通知"
2. 为什么要订阅:Event不广播,只推给订阅者,节省网络带宽
3. EventGroup:一组相关Event的集合,一次订阅收整组通知
4. 订阅流程:Subscribe → SubscribeACK → 推送通知
5. 退订:Unsubscribe(TTL=0)
6. 一句口诀:想收通知要订阅,订阅之后更便捷
写在最后
郭靖合上笔记本:"Subscribe是客户端主动订阅EventGroup。服务端收到后把客户端加入推送列表,之后Event/Notifier一发生就主动推给订阅者。不订阅,不收通知。订阅之后更便捷------不用轮询,不用广播轰炸。"
黄蓉咬了口糖葫芦:"Offer、Find、Subscribe------SD的三驾马车你都学完了。下篇咱们用完整示例把SD的整个流程串一遍。"
郭靖点头。
"下篇预告:抓个SD报文看一看,完整流程不迷路------SD完整抓包示例。"
打完收工,886。