3、DoIP协议栈架构:分层模型、实体关系与消息类型
好,咱们进入正题。DoIP协议栈,说白了就是一套让诊断数据在以太网上跑起来的规矩。我刚开始接触的时候,也觉得这东西挺复杂,但拆开来看,其实就三层:传输层、网络层、应用层。嗯,咱们一层一层说。
3.1 DoIP协议栈分层模型
DoIP协议栈,它并不是从零造轮子。它建立在标准的TCP/IP协议栈之上。我个人习惯把它看成四层,但核心的DoIP逻辑集中在三层:
| OSI层 | DoIP协议栈对应 | 典型协议/功能 |
|---|---|---|
| 应用层 | DoIP应用层 | 诊断消息(UDS)、车辆发现、路由激活 |
| 传输层 | TCP / UDP | TCP用于可靠诊断,UDP用于发现和广播 |
| 网络层 | IPv4 / IPv6 | IP地址分配、路由 |
| 数据链路层 | 以太网MAC | 100BASE-TX / 1000BASE-T / BroadR-Reach |
你想想看,为什么诊断要用TCP?因为诊断数据不能丢。我在项目中遇到过,有一次用UDP发诊断请求,结果丢了一个报文,ECU没响应,诊断仪直接报超时。排查了半天,最后发现是网络拥塞导致的。所以,DoIP的诊断消息强制走TCP,而车辆发现和状态通告这类广播消息,才用UDP。
核心要点:DoIP协议栈不是新协议,它是UDS over TCP/IP的一种封装。说白了,就是把传统的CAN诊断报文,打包成以太网帧来传输。
3.2 DoIP实体与诊断仪的关系
这里有个概念很重要——DoIP实体。它不是一个物理设备,而是一个逻辑节点。每个支持DoIP的ECU内部,都有一个DoIP实体。诊断仪本身也是一个DoIP实体。
它们之间的关系,我总结为三个角色:
- 诊断仪(Tester):主动发起连接,发送诊断请求。它就像一个问问题的人。
- DoIP网关(Gateway):通常位于中央网关中,负责路由诊断消息到目标ECU。它像一个交通指挥员。
- 目标ECU(Target ECU):实际执行诊断功能的节点。它负责回答问题。
我记得有一次调试,诊断仪死活连不上某个ECU。查了半天,发现是DoIP网关的路由表没配好。嗯,这里要注意:DoIP实体之间通过逻辑地址来识别,而不是物理地址。每个ECU都有一个16位的逻辑地址,诊断仪也有自己的逻辑地址。
避坑指南:我曾经遇到过一个问题——诊断仪发送了路由激活请求,但ECU就是不响应。后来发现,是ECU的DoIP实体没有正确配置“激活线”状态。DoIP实体在收到路由激活前,是不会处理诊断消息的。这个顺序千万别搞反。
3.3 DoIP消息类型概览
DoIP的消息类型,说白了就两大类:控制类消息和诊断类消息。控制类消息负责建立连接、管理会话;诊断类消息才是真正干活的。
我整理了一个表格,把常用的消息类型列出来:
| 消息类型 | 名称 | 用途 | 传输层 |
|---|---|---|---|
| 0x0001 | Generic DoIP header negative acknowledge | 通用否定应答,告诉对方“你发的消息我不认识” | TCP/UDP |
| 0x0002 | Vehicle Identification Request | 车辆识别请求,诊断仪用来发现车辆 | UDP |
| 0x0003 | Vehicle Identification Response | 车辆识别响应,ECU告诉诊断仪“我在这里” | UDP |
| 0x0004 | Routing Activation Request | 路由激活请求,诊断仪申请与ECU建立诊断通道 | TCP |
| 0x0005 | Routing Activation Response | 路由激活响应,ECU同意或拒绝连接 | TCP |
| 0x0006 | Alive Check Request | 心跳检测,确认对方还活着 | UDP |
| 0x0007 | Alive Check Response | 心跳应答 | UDP |
| 0x8001 | Diagnostic Message | 真正的诊断请求/响应(UDS消息) | TCP |
你可能会问,为什么要有这么多控制消息?我举个例子:车辆识别请求。诊断仪插上OBD接口后,它不知道这辆车是什么品牌、什么型号。它先发一个UDP广播,问“谁在?”。所有支持DoIP的ECU都会回复。诊断仪拿到回复后,才知道该跟谁建立TCP连接。
注意:诊断消息(0x8001)只能走TCP。为什么?因为诊断数据不能丢。你想想看,如果ECU执行了一个“写入配置”的请求,结果响应丢了,诊断仪以为没成功,又发了一次,那ECU就执行了两次。后果可能很严重。
嗯,消息类型这块,我建议你重点记住两个:路由激活(0x0004/0x0005)和诊断消息(0x8001)。这两个是实际开发中最常用的。其他的,比如Alive Check,说白了就是心跳包,用来检测连接是否还活着。我在项目中就遇到过,诊断仪和ECU之间的TCP连接因为长时间空闲被路由器断开了,结果Alive Check没通过,诊断会话自动关闭。后来我们加了一个定时发送Alive Check的机制,问题就解决了。
好了,这一章的内容就这些。下一章咱们聊聊DoIP的报文格式,看看每个字节到底是怎么定义的。到时候我会拿一个实际的抓包数据来拆解,保证你看完就能上手。