2. 车载诊断基础

好,咱们今天聊聊DoIP的协议栈。说白了,它就是一套让诊断数据能在以太网上跑起来的规矩。我刚开始接触DoIP的时候,第一反应是——这不就是把CAN诊断报文塞进以太网包里吗?后来踩了几个坑才明白,事情没那么简单。

DoIP协议栈参考了OSI七层模型,但实际落地时,我们主要关注五层:物理层、传输层、网络层、会话层和应用层。每一层各司其职,少了哪一层,诊断都跑不顺。

核心观点:DoIP不是简单地把UDS报文封装进TCP/UDP,它在每一层都做了针对车载环境的特殊设计。不理解这些设计,你写出来的诊断工具大概率会跟ECU“鸡同鸭讲”。

DoIP协议栈五层架构 应用层(Application Layer) UDS诊断服务 + DoIP消息类型 会话层(Session Layer) 路由激活、诊断连接管理、保活机制 传输层(Transport Layer) TCP(可靠诊断消息) + UDP(车辆发现) 网络层(Network Layer) IPv6/IPv4寻址、路由、DoIP实体标识 物理层(Physical Layer) 100BASE-T1 / 1000BASE-T1 车载以太网 诊断仪(Tester)与ECU之间的所有诊断交互,都在这五层中完成封装与解析

2.1 物理层——车上的“网线”长什么样

物理层是协议栈的基石。DoIP的物理层用的是车载以太网,不是咱们办公室里的那种RJ45网口。车上用的是100BASE-T1或1000BASE-T1,一对差分线搞定收发。

我记得第一次在台架上调试DoIP,拿了一根普通网线插上去,ECU死活不通。后来才发现,车载以太网的物理层用了不同的编码方式和共模电压。嗯,这个坑我替你们踩过了。

特性 100BASE-T1 标准以太网(100BASE-TX)
线对数量 1对差分线 2对差分线
连接器 专用车载连接器 RJ45
共模电压 1.5V ~ 2.5V 0V
主要应用 车载诊断、音视频 办公网络

实战建议:做DoIP测试时,务必确认物理层是100BASE-T1还是1000BASE-T1。两者不兼容,插错了没反应。我习惯在测试前先用示波器看差分信号幅值,确认物理层在正常工作。

2.2 网络层——给ECU发个“门牌号”

网络层负责寻址和路由。DoIP强制要求支持IPv6,同时兼容IPv4。为什么用IPv6?你想想看,一辆车上几十个ECU,未来还有V2X,IPv4的地址空间根本不够用。

每个支持DoIP的ECU都有一个逻辑地址(Logical Address),比如0x0E80代表网关,0x1001代表发动机ECU。诊断仪发请求时,网络层会把逻辑地址映射到IP地址上。

注意:DoIP的“车辆发现”功能依赖网络层的广播/组播机制。诊断仪通过UDP广播发送车辆识别请求(VIN),ECU回复自己的IP和逻辑地址。如果网络层配置不对,诊断仪可能连车都“找”不到。

2.3 传输层——TCP还是UDP?看场景

传输层是DoIP的“交通调度员”。它用了两种协议:

  • TCP(端口13400):用于诊断消息的可靠传输。说白了,诊断请求和响应必须一个不丢、顺序不乱,所以用TCP。
  • UDP(端口13400):用于车辆发现和诊断连接状态通告。这些消息不需要确认,丢了可以重发,UDP更高效。

我遇到过一个问题:诊断仪发了一个路由激活请求,ECU没回。查了半天,发现是TCP连接被中间设备重置了。后来我在代码里加了TCP keep-alive,问题就解决了。

2.4 会话层——握个手,建立连接

会话层是DoIP协议栈里最“有存在感”的一层。它负责:

  1. 路由激活(Routing Activation):诊断仪发一个激活请求,ECU验证后建立诊断路由。
  2. 诊断连接管理:每个诊断会话都有一个唯一的连接ID,防止多个诊断仪冲突。
  3. 保活机制(Alive Check):定期发送保活消息,检测连接是否还活着。

说白了,会话层就是诊断仪和ECU之间的“握手”和“心跳”。没有会话层,你连诊断通道都打不开。

避坑指南:我曾经在实车测试时,诊断仪连上后几分钟就断开了。查日志发现是ECU的保活定时器设得太短,诊断仪没来得及回复。后来我把保活间隔统一设为5秒,两边对齐,问题解决。

2.5 应用层——UDS诊断报文在这里

应用层是咱们最熟悉的一层。它承载了UDS诊断服务,比如读取故障码(0x19)、读取数据(0x22)、写入数据(0x2E)等。DoIP的应用层在UDS报文外面包了一层DoIP头部,用来标识消息类型和长度。

一个典型的DoIP诊断请求长这样:

| DoIP头部 (8字节) | UDS请求 (N字节) |
| 协议版本 | 消息类型 | 负载长度 | 用户数据 |

举个例子,读取VIN的UDS请求(0x22 0xF1 0x90),在DoIP里会变成:

02 FD 80 00 00 00 00 03 22 F1 90
|-- DoIP头部 --| |-- UDS --|

其中02 FD是协议版本和消息类型,80 00是连接ID,00 00 00 03表示后面UDS数据有3个字节。

小技巧:调试DoIP应用层时,我习惯先用Wireshark抓包,过滤条件设为tcp.port == 13400。这样能清晰看到DoIP头部和UDS报文的对应关系,排查问题特别快。

2.6 五层协作——一个诊断请求的完整旅程

咱们用一个实际场景串一遍:诊断仪想读取发动机ECU的故障码数量。

层级 做的事情
应用层 构造UDS请求:0x19 0x01(读取故障码数量)
会话层 检查诊断连接是否激活,分配连接ID
传输层 将数据通过TCP连接发送到ECU的13400端口
网络层 根据ECU的逻辑地址,找到对应的IPv6地址,封装IP包
物理层 将数字信号转换成差分信号,在100BASE-T1线对上传输

ECU收到后,按相反顺序逐层解包,最终把UDS请求交给诊断应用处理。整个过程,从诊断仪按下“读取”按钮到ECU响应,通常不超过50毫秒。

性能提醒:如果某层处理慢了,整个诊断链路都会变慢。我见过一个案例,ECU的TCP窗口设置太小,导致诊断响应被分成了好几个包,应用层等了很久才拼完整。调大TCP窗口后,响应时间从200ms降到了30ms。

好了,DoIP协议栈的五层架构就聊到这儿。每一层都有它的设计逻辑和坑点,理解了这些,后面咱们讲具体实现时,你就能更快上手了。