4、DoIP车辆发现与声明:VIN/GID/EID的作用、车辆声明报文、车辆识别请求与响应

好,咱们进入第四章。这一章讲的是DoIP里一个非常核心的环节——车辆发现

你想想看,诊断仪插到车上,或者连上车载以太网,它怎么知道对面是什么车?是宝马还是大众?VIN是多少?支持哪些诊断功能?

嗯,这就是车辆发现要解决的问题。说白了,就是让诊断工具和车辆“对上暗号”,互相认识一下。

4.1 三个关键ID:VIN、GID、EID

在DoIP协议里,车辆用三个标识符来表明身份。我刚开始接触的时候,也容易搞混,咱们一个一个捋清楚。

标识符 全称 长度 作用
VIN Vehicle Identification Number 17字节 车辆唯一身份,全球唯一
EID Entity Identification 6字节 网关/实体的硬件唯一标识
GID Group Identification 6字节 逻辑分组标识,用于多网关场景

VIN 大家最熟悉,就是车架号。17位,包含制造商、车型、年份等信息。在DoIP里,VIN是最高级别的标识。诊断仪拿到VIN,基本就知道该用哪套诊断数据库了。

EID 呢,我个人习惯叫它“硬件身份证”。它是网关控制器出厂时烧录的唯一ID,6个字节,通常基于MAC地址或者芯片序列号生成。EID在VIN还没设置的时候特别有用——比如新车下线前,VIN还是空的,这时候诊断仪就靠EID来识别具体的网关。

GID 用得相对少一些。它用于逻辑分组。举个例子,一辆车可能有多个DoIP实体(比如两个网关),它们可以属于同一个GID组。诊断仪可以通过GID一次性发现一组设备。

重点记忆:

  • VIN = 车辆身份证(最终目标)
  • EID = 硬件身份证(出厂就有)
  • GID = 逻辑分组(可选,用于多实体)

4.2 车辆声明报文(Vehicle Announcement)

车辆声明,是DoIP实体主动“打招呼”的方式。它有两种触发场景:

  1. 上电自动发送:车辆网关一上电,就会主动广播一条车辆声明报文。
  2. 收到诊断仪的请求后回复:诊断仪发一个广播请求,所有DoIP实体回复声明。

报文格式长什么样?咱们直接看代码:

// 车辆声明报文结构(UDP广播,端口13400)
// 协议版本:0x02 (ISO 13400-2:2012)
// 负载类型:0x0004 (Vehicle Announcement)

Byte 0-1: 协议版本 (0x02) + 反向版本 (0xFD)
Byte 2-3: 负载类型 (0x0004)
Byte 4-7: 负载长度 (0x00000015 = 21字节)
Byte 8:    VIN/GID/EID 逻辑地址
Byte 9-10: 实体类型 (0x0001 = 网关)
Byte 11:    DoIP支持的最大并发连接数
Byte 12:    已建立的DoIP连接数
Byte 13-29: VIN (17字节,不足补0x00)
Byte 30-35: EID (6字节)
Byte 36-41: GID (6字节,可选,无则全0)
Byte 42-43: 进一步动作标志 (0x0000)

我在项目中遇到过一个问题:某款车在VIN还没写入的时候,车辆声明报文里的VIN字段全是0x00。诊断仪收到后直接忽略了这个节点,导致无法连接。后来排查发现,诊断仪的逻辑是“VIN为空就不处理”。

嗯,这里要注意:VIN为空时,诊断仪应该退而求其次,用EID来识别车辆。这是协议允许的,也是实际开发中容易踩的坑。

实战技巧:

我曾经调试过一个项目,车辆声明报文总是收不到。抓包一看,发现网关的UDP广播端口写错了,写成了13401。记住,DoIP的UDP端口固定是13400,TCP端口也是13400。别搞混。

4.3 车辆识别请求与响应

除了主动声明,诊断仪也可以主动发起“车辆识别请求”。这就像你到了停车场,喊一声“谁是宝马X5?”,然后符合条件的车会回应你。

车辆识别请求分为两种:

  • 广播请求:发给所有DoIP实体(目标地址0xFFFF)
  • 单播请求:发给指定EID或VIN的实体

4.3.1 广播请求(谁在?)

诊断仪发送一个UDP广播报文,负载类型为0x0001(Vehicle Identification Request)。所有收到这个报文的DoIP实体,都必须回复车辆声明报文。

// 诊断仪发送的车辆识别请求(广播)
// 目标地址:255.255.255.255:13400
// 负载类型:0x0001

Byte 0-1: 协议版本 (0x02) + 反向版本 (0xFD)
Byte 2-3: 负载类型 (0x0001)
Byte 4-7: 负载长度 (0x00000000)  // 请求本身没有额外数据

你想想看,这个请求只有8个字节,非常轻量。但回复的车辆声明报文有40多字节。这就是典型的“小请求,大回复”模式。

4.3.2 单播请求(指定VIN或EID)

如果诊断仪已经知道某个车辆的VIN或EID,可以发送单播请求,只让那辆车回复。

// 按VIN请求(负载类型:0x0002)
Byte 0-7: 报文头
Byte 8-24: VIN (17字节)

// 按EID请求(负载类型:0x0003)
Byte 0-7: 报文头
Byte 8-13: EID (6字节)

我记得有一次,客户反馈说诊断仪连不上某辆测试车。我远程抓包一看,诊断仪发了按VIN的识别请求,但VIN里有一个字母大小写不对。DoIP协议规定VIN比较是大小写敏感的。嗯,这种低级错误,排查起来最费时间。

避坑指南:

我曾经遇到一个奇葩问题:车辆声明报文里的VIN和EID都正确,但诊断仪就是识别不到。最后发现,是网关的UDP回复报文被防火墙拦截了。车载以太网环境下,有些交换机或防火墙会过滤UDP广播包。建议在开发阶段,先用抓包工具确认报文是否真的发出来了。

4.4 车辆发现的完整流程

咱们把整个流程串起来,看看实际工作中是怎么用的。

  1. 车辆上电:网关启动,发送车辆声明报文(UDP广播)。
  2. 诊断仪监听:诊断仪收到声明,解析VIN/EID/GID。
  3. 诊断仪确认:如果VIN有效,直接使用;如果VIN为空,用EID匹配。
  4. 建立TCP连接:诊断仪根据声明报文中的逻辑地址,发起TCP连接(端口13400)。
  5. 路由激活:TCP连接建立后,进行路由激活,正式进入诊断会话。

这个流程看起来简单,但实际开发中,每一步都可能出问题。我建议你在做DoIP测试时,第一步就是抓取车辆声明报文。如果连这个报文都收不到,后面的所有工作都是白搭。

核心要点总结:

  • 车辆发现是DoIP通信的第一步,靠UDP广播实现
  • VIN是最终标识,EID是备用标识,GID用于分组
  • 车辆声明报文在车辆上电时自动发送,也可由诊断仪请求触发
  • 诊断仪收到声明后,根据VIN或EID决定是否建立TCP连接
  • 实际开发中,注意VIN为空、大小写敏感、UDP广播被过滤等坑

好,这一章就到这里。下一章咱们聊聊TCP连接建立和路由激活,那是真正开始“对话”的关键步骤。