1. DoIP协议基础:从物理层到消息头,一个都不能少

大家好,我是你们的老朋友。今天咱们正式开讲DoIP协议基础。说实话,我最早接触DoIP是在2015年,那时候车载以太网还是个新鲜玩意儿。记得第一次用DoIP刷写ECU,折腾了一整天没连上,最后发现是端口号搞错了。嗯,这些坑我会在课程里一一帮你们避开。

DoIP,全称Diagnostic over Internet Protocol。说白了,就是把传统的CAN诊断搬到以太网上。为什么要这么做?你想想看,现在一辆车里有上百个ECU,CAN总线的带宽早就捉襟见肘了。以太网一上来,带宽直接翻了几百倍,刷个固件从半小时变成两分钟,这感觉,爽。

1.1 DoIP协议栈概述

DoIP协议栈长什么样?我习惯把它分成四层来看:

  • 物理层:100BASE-T1或1000BASE-T1,就是车载以太网的物理介质
  • 传输层:TCP和UDP,一个可靠一个快速,各司其职
  • 网络层:IPv4或IPv6,负责寻址和路由
  • 应用层:DoIP协议本身,封装UDS诊断消息

我在项目中遇到过一种情况:有人把DoIP和UDS混为一谈。其实DoIP是运输工具,UDS是货物。DoIP负责把UDS诊断请求从诊断仪送到ECU,再把响应带回来。没有DoIP,UDS也能跑在CAN上;没有UDS,DoIP就是个空壳子。

核心要点:DoIP协议栈的核心价值在于,它让诊断通信从CAN的1Mbps瓶颈,跃升到以太网的100Mbps甚至更高。这不是量变,是质变。

1.2 物理层与传输层

物理层这块,车载以太网和普通以太网不太一样。普通以太网用RJ45接口,四对差分线。车载以太网用100BASE-T1,只有一对差分线,而且支持PoDL(Power over Data Line),就是数据线上也能供电。

我记得第一次调试DoIP物理层,示波器一测,波形怎么都不对。后来发现是线束太长,超过了15米。车载以太网虽然理论上支持到40米,但实际项目中我建议控制在10米以内,尤其是做压力测试的时候,线缆质量直接影响丢包率。

传输层这块,TCP和UDP的分工很明确:

协议 端口 用途 可靠性
UDP 13400 车辆发现、节点公告 不可靠,但速度快
TCP 13400 诊断消息传输、路由激活 可靠,保证顺序

为什么会这样设计?你想想看,车辆发现阶段,诊断仪需要广播一个请求,所有ECU都要响应。如果用TCP,每个ECU都要建立连接,效率太低。UDP一发广播,所有节点都能收到,简单粗暴。但诊断消息就不一样了,丢一个字节都可能出大问题,所以必须用TCP。

我的经验:做压力测试时,UDP端口可以同时处理多个广播请求,但TCP端口同一时间只能处理一个连接。我曾经遇到过诊断仪同时连接多个ECU时,TCP端口被占满导致新连接失败的情况。解决方案是增加端口复用,或者缩短连接保持时间。

1.3 DoIP消息头结构解析

DoIP消息头,这是今天最核心的内容。每个DoIP消息都有一个固定的头部结构,一共8个字节:

字节0-1: 协议版本 (Protocol Version)
  0x02 - ISO 13400-2:2012
  0x03 - ISO 13400-2:2019

字节2-3: 负载类型 (Payload Type)
  0x0001 - 车辆识别请求
  0x0002 - 车辆识别响应
  0x0003 - 路由激活请求
  0x0004 - 路由激活响应
  0x8001 - 诊断消息
  0x8002 - 诊断消息确认

字节4-7: 负载长度 (Payload Length)
  表示后续负载数据的字节数
  最大长度取决于传输层MTU

嗯,这里要注意一个细节。协议版本字段,很多人以为填0x02就够了。但我在2019年的项目里就踩过坑:新版本的ECU要求协议版本必须是0x03,否则直接拒绝连接。所以写代码的时候,最好先读一下ECU支持的版本,再决定用哪个。

负载类型字段,我习惯把它想象成「信封上的邮戳」。不同的邮戳代表不同的信件类型。比如0x0001是「我在找车」,0x8001是「我要诊断」。诊断仪和ECU就是靠这个字段来区分消息用途的。

负载长度字段,这个最容易出错。我曾经见过一个同事,把负载长度写成了整个消息的长度,包括头部。结果ECU解析的时候,多读了8个字节,后面的消息全乱了。记住:负载长度只算头部后面的数据,头部本身不算。

避坑指南:我曾经在压力测试中发现,当负载长度字段填0时,有些ECU会直接忽略这条消息,有些则会报错。所以即使没有负载数据,也建议填0而不是不填。这是ISO 13400-2明确规定的,别偷懒。

1.4 实际应用中的小技巧

讲完理论,说点实际的。做DoIP开发,我建议你准备一个抓包工具。Wireshark就挺好,装上DoIP解析插件,每个消息头都能看得清清楚楚。我调试的时候,习惯先抓一把正常的通信包,再对比出问题的包,问题往往一目了然。

还有一个技巧:做多节点并发测试时,记得给每个ECU分配不同的逻辑地址。逻辑地址是DoIP用来区分不同ECU的标识,类似于CAN诊断中的物理地址。如果两个ECU用了相同的逻辑地址,诊断仪就分不清谁是谁了。我见过最离谱的一次,同一辆车上三个ECU都配了0x1001,结果诊断仪一广播,三个同时响应,直接把网络搞瘫了。

好了,这一章的内容就到这里。DoIP协议基础是后面所有章节的基石,尤其是消息头结构,一定要烂熟于心。下一章我们讲车辆发现机制,就是诊断仪怎么找到车上的ECU。到时候我会分享一个我当年调试车辆发现功能时遇到的奇葩问题,保证让你印象深刻。