写在开篇·蓉儿继续挖坑
上回说到,郭靖搞清楚了Method和Event的区别——Method是你问他答,Event是它自己说。
郭靖合上笔记本,信心满满:“蓉儿,Method就是发个请求,等个响应,对吧?”
黄蓉咬了口糖葫芦:“那好,我问你——座舱控制左前车窗升窗,如果不在乎车窗到底升没升上去,只想喊一嗓子‘升窗’,喊完就走,不用等它回复,该用什么?”
郭靖一愣:“这……还能这样?那要是电机卡住了怎么办?”
“那就是另一种Method:Fire&Forget。今天就把Method的两种模式讲透,顺便把Session ID、Client ID、Payload数据全串起来。”
附:SOME/IP报文结构速查表
Method的两种模式靠Message Type区分。Session ID和Client ID是配对的关键。
| 字节偏移 | 字段 | 长度 | 说明 |
|---|---|---|---|
| 0-1 | Service ID | 16位 | 服务的唯一标识(车窗=0x0300) |
| 2-3 | Method ID | 16位 | 最高位=0 |
| 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位 | 0x00=REQUEST,0x01=REQUEST_NO_RETURN,0x80=RESPONSE |
| 15 | Return Code | 8位 | 返回码,0x00=E_OK |
| 16... | Payload | 可变 | 载荷数据,Instance ID在头2字节,后面跟业务参数 |
一、Method的两种模式
黄蓉在白板上画了一张表:
| Message Type | 值 | 名称 | 说明 | 有没有响应 |
|---|---|---|---|---|
0x00 | REQUEST | 请求-响应模式(Request-Response) | 你问他答,必须有响应 | ✅ 有 |
0x01 | REQUEST_NO_RETURN | 只发不收模式(Fire&Forget) | 喊一嗓子不管了 | ❌ 无 |
0x80 | RESPONSE | 响应 | 回复之前的REQUEST | — |
郭靖挠头:“Fire&Forget?喊完就走?那车窗到底升没升上去都不知道啊。”
黄蓉:“你说得对。Fire&Forget不适合需要确认的场景。但有些场景根本不关心结果——比如按下‘氛围灯颜色切换’按钮,灯变不变你都能看见,不需要ECU回一个‘OK’。而升窗涉及安全(防夹手),必须知道执行结果,所以要用Request-Response。”
二、Request-Response模式(一问一答)
场景:座舱想知道左前车窗当前的位置。需要车窗回复具体数值,必须用Request-Response。
时序图(带Client ID和Session ID匹配):
座舱(Client ID=0x1234) 车窗(Server) │ │ │ REQUEST (Message Type=0x00) │ │ Service ID=0x0300 │ │ Method ID=0x0003(查询位置) │ │ Client ID=0x1234 │ │ Session ID=0x0001 ← 第一次请求 │ │ Payload: [Instance ID=0x0001] │ │──────────────────────────────────────────>│ │ │ │ RESPONSE (Message Type=0x80) │ │ Service ID=0x0300 │ │ Method ID=0x0003(原样返回) │ │ Client ID=0x1234 │ │ Session ID=0x0001 ← 同样的Session ID │ │ Return Code=0x00(E_OK) │ │ Payload: [Instance ID][位置=0x32(50%)] │ │<──────────────────────────────────────────│
关键点:
| 要素 | 说明 |
|---|---|
| Client ID | 标识是哪个客户端发的(座舱=0x1234,音响=0x5678),多客户端时不会串 |
| Session ID | 客户端每次请求+1,服务端响应时原样回传,客户端根据Session ID匹配哪个请求对应哪个响应 |
| Method ID | 请求和响应中相同,告诉客户端“这是对哪个方法的响应” |
| Payload | 请求可带参数(Instance ID),响应可带返回数据(位置值、结果码) |
完整16进制报文示例(查询位置):
| 方向 | 十六进制 | 解析 |
|---|---|---|
| 请求 | 03 00 00 03 00 00 00 08 12 34 00 01 01 01 00 00 | 00 01 | Service ID=0x0300,Method ID=0x0003,Client ID=0x1234,Session ID=0x0001,Message Type=0x00,Payload Instance ID=0x0001 |
| 响应 | 03 00 00 03 00 00 00 09 12 34 00 01 01 01 80 00 | 00 01 32 | Method ID相同,Client ID相同,Session ID相同,Message Type=0x80,Return Code=0x00,Payload Instance ID=0x0001 + 位置数据0x32(50%) |
三、Fire&Forget模式(只发不收)
场景:座舱让氛围灯切换到“蓝色”,不需要灯回复“我变蓝了”——人眼能看见。
黄蓉画了没有响应的时序图:
座舱(Client ID=0x1234) 氛围灯服务(Server) │ │ │ REQUEST_NO_RETURN (Message Type=0x01) │ │ Service ID=0x0400 │ │ Method ID=0x0001(切换颜色) │ │ Client ID=0x1234 │ │ Session ID=0x0002(仍可递增) │ │ Payload: [Instance ID=0x0001][颜色=蓝色] │ │──────────────────────────────────────────>│ │ │ │ (没有RESPONSE!服务端直接执行) │ │ (如果失败?没人知道,人眼看) │
关键点:
| 要素 | Fire&Forget的行为 |
|---|---|
| Message Type | 0x01(REQUEST_NO_RETURN) |
| 有没有响应 | ❌ 没有。服务端不返回RESPONSE |
| Session ID | 仍然可以递增(用于日志/调试),但客户端不需要用它匹配响应(因为没有响应) |
| 适用场景 | 不关心执行结果的操作,比如切换氛围灯、音量步进+1(失败了下一次再按) |
郭靖追问:“那车窗升窗能用Fire&Forget吗?如果电机卡住了,座舱不知道,用户以为升了但窗没动……”
黄蓉摇头:“不能。升窗涉及安全(防夹手),必须知道执行结果。失败时要报警或重试。安全相关的操作必须用Request-Response。”
四、Session ID详解——为什么要有它?
郭靖盯着报文结构表:“Session ID到底是干啥的?不就是个数字吗?”
黄蓉画了一个并发请求的场景:
座舱 车窗 │ REQUEST: Session ID=0x0001(查询位置) │ │─────────────────────────────────────────>│ │ REQUEST: Session ID=0x0002(升窗) │(车窗还没回复第一个请求) │─────────────────────────────────────────>│ │ │ │ RESPONSE: Session ID=0x0001(位置=50%) │ ← 客户端知道这是对第一个请求的响应 │<─────────────────────────────────────────│ │ RESPONSE: Session ID=0x0002(升窗成功) │ ← 客户端知道这是对第二个请求的响应 │<─────────────────────────────────────────│
“如果没有Session ID,车窗先回复‘50%’还是先回复‘升窗成功’?座舱根本分不清哪个响应是对应哪个请求的。Session ID把请求和响应配对。”
郭靖点头:“哦~~就像寄快递,每个包裹有个单号,回执上印着同样的单号,你才知道哪张回执对应哪个包裹。”
五、Client ID详解——多客户端不打架
郭靖又问:“那Client ID呢?有什么用?”
黄蓉画了两个客户端同时请求的场景:
座舱(Client ID=0x1234) 车窗 音响(Client ID=0x5678) │ REQUEST: Session ID=0x0001 │ │ │──────────────────────────────────>│ │ │ │ REQUEST: Session ID=0x0001│ │ │<──────────────────────────│ │ │ │ │ RESPONSE: Client=0x1234,Sess=0x0001 │ │<──────────────────────────────────│ │ │ │ RESPONSE: Client=0x5678,Sess=0x0001│ │ │──────────────────────────>│
“车窗同时收到座舱和音响的请求。回复时,Client ID告诉车窗:这个响应是给谁的。座舱收到Client=0x1234的响应才收,Client=0x5678的响应交给音响。各拿各的,不会乱。”
六、Request-Response vs Fire&Forget 完整对比
黄蓉把两种模式的异同点整理成一张大表:
| 对比项 | Request-Response | Fire&Forget |
|---|---|---|
| Message Type | 0x00(REQUEST) +0x80(RESPONSE) | 0x01(REQUEST_NO_RETURN) |
| 有没有响应 | ✅ 有 | ❌ 无 |
| 需要Session ID配对 | ✅ 必须,响应与请求Session ID相同 | 可选(无响应,不需要配对);可用于日志/调试 |
| Client ID用途 | 区分响应归哪个客户端 | 仍可区分请求来源(但无响应,主要用于日志) |
| 适用场景 | 需要确认结果的操作 | 不关心结果的操作 |
| 车窗例子 | 升窗、降窗、查询位置 | 不适合(升窗需要确认) |
| 氛围灯例子 | 不适合(不需要确认) | 切换颜色 |
七、黄蓉的小本本
郭靖翻开她的笔记本,上面写着:
Request-Response(Message Type 0x00 + 0x80)
一问一答,必须配对
Session ID用于匹配请求和响应(客户端递增,服务端原样返回)
Client ID区分不同调用者
响应可带数据(位置、结果码)
Fire&Forget(Message Type 0x01)
只发不收,不需要响应
Session ID可选(通常仍递增,便于追踪)
Client ID仍可标识来源
适合不关心结果的操作
安全相关操作(如车窗)必须用Request-Response,Fire&Forget不可用于需要确认的场景。
写在最后
郭靖合上笔记本:“Request-Response是一问一答,Fire&Forget是喊完就走。Session ID配对请求响应,Client ID区分谁是谁。”
黄蓉咬了口糖葫芦:“那你现在知道了Method的两种模式,知道Field是什么吗?Field既能读又能写还能订阅,比Method更灵活。”
郭靖摇头。
“和上篇同样的下篇预告:能读能写是Field,Getter/Setter要分明——Field是个啥?”
打完收工,886。