写在开篇·蓉儿继续挖坑

上回说到,郭靖搞清楚了Service ID(什么服务)和Instance ID(第几个)。车窗服务是0x0300,左前窗是0x0001。
郭靖合上笔记本,信心满满:"蓉儿,Service ID和Instance ID我搞明白了!发个升窗报文,Service ID=0x0300,Instance ID=0x0001,Method ID=0x0001,就能让左前窗升上去。"
黄蓉咬了口糖葫芦:"那好,我问你------如果你想知道左前窗现在的位置,你是发一个查询请求等它回复,还是等着它自己主动告诉你?"
郭靖一愣:"这......有什么区别吗?"
"一个是你问他答,一个是它自己说。这就是Method和Event的区别。今天就把这个讲透。"
附:SOME/IP报文结构速查表
Method和Event共用报文头的第2-3字节(Method ID/Event ID),靠最高位区分。别忘了这个表。
| 字节偏移 | 字段 | 长度 | 说明 |
|---|---|---|---|
| 0-1 | Service ID | 16位 | 服务的唯一标识(车窗=0x0300) |
| 2-3 | Method ID / Event ID | 16位 | 最高位=0是Method,=1是Event |
| 4-7 | Length | 32位 | 从Request ID开始到报文结束的总长度 |
| 8-9 | Client ID | 16位 | 客户端标识 |
| 10-11 | Session ID | 16位 | 会话标识,用于匹配请求和响应 |
| 12 | Protocol Version | 8位 | 协议版本号,当前固定为0x01 |
| 13 | Interface Version | 8位 | 服务接口的版本号 |
| 14 | Message Type | 8位 | 消息类型:REQUEST=0x00,RESPONSE=0x80,NOTIFICATION=0x02 |
| 15 | Return Code | 8位 | 返回码 |
| 16... | Payload | 可变 | 载荷数据,Instance ID在头2字节 |
一、Method是什么------你问他答(REQUEST + RESPONSE)
郭靖问:"先说说Method,到底什么样算Method?"
黄蓉画了一张时序图,并标出每一条消息的Message Type和Payload:
座舱(客户端) 车窗(服务端)
│ │
│ ① REQUEST(查询位置) │
│ Message Type = 0x00 │
│ Service ID=0x0300 │
│ Instance ID=0x0001(载荷里) │
│ Method ID=0x0003(查询位置) │
│ 载荷:[Instance ID][空/无参数] │
│──────────────────────────────────────>│
│ │
│ ② RESPONSE(返回50%) │
│ Message Type = 0x80 │
│ Service ID=0x0300 │
│ Instance ID=0x0001 │
│ Method ID=0x0003(原样返回) │
│ 载荷:[Instance ID][位置数据=0x32] │
│<──────────────────────────────────────│
"Method = 一问一答 。客户端发REQUEST,服务端执行后返回RESPONSE。Response里通常会带一个数据(比如查询到的位置)。注意,Method ID在请求和响应里是一样的,用来把响应和请求配对。"
车窗服务中的Method例子:
| 操作 | Method ID | 请求Payload | 响应Payload | 说明 |
|---|---|---|---|---|
| 升窗 | 0x0001 |
Instance ID + 0x01(升窗命令) | Instance ID + 结果码 | 请求执行,响应确认 |
| 降窗 | 0x0002 |
Instance ID + 0x02(降窗命令) | Instance ID + 结果码 | 请求执行,响应确认 |
| 查询位置 | 0x0003 |
Instance ID(无其他参数) | Instance ID + 当前位置(0x32) | 响应里带了数据 |
郭靖指着表格问:"所以Method的响应里可以带数据?不只是一个'收到了'?"
黄蓉:"对!查询位置就是典型例子。你问'现在多少',它回答'50%',数据在响应的Payload里。这叫请求-响应模式带数据。升窗降窗也可以带结果码告诉你是成功还是失败(电机卡住等)。"
二、Method Fire&Forget------只发不收
黄蓉补充道:"Method还有一种变体,叫Fire&Forget------只发不收,不需要响应。"
| 场景 | 例子 | 说明 |
|---|---|---|
| 升窗不关心结果 | "升窗",喊完就走 | Message Type = 0x01(REQUEST_NO_RETURN) |
| ECU不返回响应 | 车窗执行即可,无需确认 | 没有RESPONSE |
"这种适合那些不需要确认的操作。但车窗升窗通常还是需要确认的,怕卡住。"
三、Event是什么------它自己说(NOTIFICATION)
郭靖又问:"那Event呢?Event的Notification里带不带数据?"
黄蓉画了第二张时序图:
座舱(客户端) 车窗(服务端)
│ │
│ (车窗位置从0%变到50%) │
│ │
│ ① NOTIFICATION(位置变化通知) │
│ Message Type = 0x02 │
│ Service ID=0x0300 │
│ Instance ID=0x0001 │
│ Event ID=0x8001(位置变化) │
│ 载荷:[Instance ID][当前位置=0x32] │
│<──────────────────────────────────────│
│ │
│ (车窗位置从50%变到80%) │
│ ② NOTIFICATION(位置变化通知) │
│ 载荷:[Instance ID][当前位置=0x50] │
│<──────────────────────────────────────│
"Event = 它自己说,不等你问。 服务端状态变化时,主动发NOTIFICATION。Notification里也带数据------当前位置是多少。这样客户端不用问就知道新位置。"
"Event不需要响应,是单向的。客户端只管收,不用回。"
车窗服务中的Event例子:
| 事件 | Event ID | 触发条件 | 载荷数据 | 说明 |
|---|---|---|---|---|
| 位置变化事件 | 0x8001 |
车窗位置发生变化 | Instance ID + 当前位置(0x32/0x50等) | 通知里带位置数据 |
郭靖恍然大悟:"所以Event的Notification里也带数据,告诉客户端'现在是多少'。客户端不用再去查一次。"
四、Method vs Event:关键区别(含Message Type和Payload对比)
郭靖盯着两张图看了一会儿:
"那Method和Event到底有什么区别?我看响应和通知里都带数据啊。"
黄蓉列了一张完整的对比表:
| 对比项 | Method | Event |
|---|---|---|
| 谁发起 | 客户端主动问 | 服务端主动说 |
| 有没有响应 | 有(RESPONSE),MUST NOT be used for Events | 无(NOTIFICATION单向) |
| 触发条件 | 客户端需要时才发 | 服务端状态变化时自动发 |
| Message Type | REQUEST(0x00) / RESPONSE(0x80) / REQUEST_NO_RETURN(0x01) | NOTIFICATION(0x02) |
| ID范围 | 0x0001-0x7FFF |
0x8000-0xFFFF |
| 是否需要Session ID | 需要,用于匹配请求和响应 | 可选(不要求) |
| Payload数据 | 请求可带参数,响应可带返回数据 | 通知里带当前状态数据 |
| 车窗例子 | 查询位置(0x0003):请求无参数,响应带位置 |
位置变化事件(0x8001):通知里带变化后的位置 |
| 类比 | 你打电话问"几点了",对方回答"三点" | 闹钟到点自己响,还告诉你"几点了" |
"关键区别:Method是你先问,它才答。Event是它变了就主动说。两者都可能在Payload里带数据。"
五、一个真实的服务定义表(Method + Event + Payload)
黄蓉从电脑里调出完整的车窗服务定义表,这次把Payload也列了进去:
| Service ID | Instance ID | Method/Event ID | 类型 | 名称 | 请求Payload | 响应/通知Payload |
|---|---|---|---|---|---|---|
0x0300 |
0x0001 |
0x0001 |
Method(RR) | 升窗 | Instance ID + 升窗命令 | Instance ID + 结果码 |
0x0300 |
0x0001 |
0x0002 |
Method(RR) | 降窗 | Instance ID + 降窗命令 | Instance ID + 结果码 |
0x0300 |
0x0001 |
0x0003 |
Method(RR) | 查询位置 | Instance ID | Instance ID + 当前位置(1字节) |
0x0300 |
0x0001 |
0x8001 |
Event | 位置变化 | --- | Instance ID + 当前位置(1字节) |
郭靖指着Event那一行:"Event的通知Payload里也带了当前位置,那客户端收到后直接就知道新位置了,不用再发Method查询?"
黄蓉:"对!这就是Event的价值------状态变化时主动推送,减少轮询,降低网络负载。 如果你不用Event,就得每隔100ms发一次Method去查位置,浪费带宽。"
六、为什么Event ID以8开头
郭靖又问:"Event ID是0x8001,和Method ID0x0001的最高位不同。这个最高位的作用是什么?"
黄蓉指着报文头的第2-3字节:
"因为Method ID和Event ID共用同一个16位字段,靠最高位区分。接收方收到报文后,先看第17位(从0开始数的第16位),就知道下面该怎么解析。"
| 第17位 | ID范围 | 类型 | Message Type典型值 |
|---|---|---|---|
| 0 | 0x0001-0x7FFF |
Method ID | 0x00(REQUEST)、0x80(RESPONSE) |
| 1 | 0x8000-0xFFFF |
Event ID | 0x02(NOTIFICATION) |
"这个设计在讲Message ID构造规则时会详细说。今天你只需要记住:Method和Event在报文头里用的是同一个位置,但看最高位就知道是哪个,处理方式也不同。"
七、黄蓉的小本本
郭靖翻开她的笔记本,上面写着:
Method = 你问他答
客户端发REQUEST(0x00),服务端回RESPONSE(0x80)
需要Session ID配对
请求可带参数,响应可带数据(如查询结果)
Event = 它自己说
服务端发NOTIFICATION(0x02)
不需要响应,Session ID可选
通知里带当前状态数据
两者都可能在Payload里带数据
ID区分 :Method ID=
0x0001-0x7FFF,Event ID=0x8000-0xFFFF,看最高位就知道类型
写在最后
郭靖合上笔记本:"Method是请求-响应带数据,Event是通知带数据。Method是你先问它,它才答;Event是它变了就主动说。"
黄蓉咬了口糖葫芦:"那你知道了Method和Event,知道Field是什么吗?Field既能读又能写还能订阅,比Method和Event都灵活。"
郭靖摇头。
"下篇预告:能读能写是Field,Getter/Setter要分明------Field是个啥?"
打完收工,886。