2、DoIP物理层与传输层:以太网物理层要求、TCP/UDP端口分配、DoIP报文封装格式

2.1 以太网物理层要求——别小看这根线

做DoIP,首先得把物理层搞定。说白了,就是你的车和诊断仪之间,到底用什么样的网线、什么样的接口来连。

我个人习惯把物理层分成两块来看:车载端诊断仪端

车载端现在主流是100BASE-T1(也叫BroadR-Reach)。它只用一对双绞线,就能跑100Mbps。我记得第一次在项目里看到这个,心里还犯嘀咕:一对线?能稳定吗?后来实测发现,只要线束质量过关,完全没问题。它比传统的100BASE-TX少了两对线,对整车线束减重很有帮助。

诊断仪端呢?通常是100BASE-TX或1000BASE-T。就是咱们电脑上常见的RJ45接口,四对线。这个大家都很熟了,我就不多啰嗦。

这里有个坑,我曾经踩过——连接器选型。车载端不能用普通的RJ45,得用专用的车载以太网连接器(比如H-MTD、MATEnet)。普通RJ45的机械强度不够,车一颠簸就容易接触不良。嗯,这一点你设计时一定要跟线束供应商确认清楚。

物理层关键参数速查表

参数 100BASE-T1(车载) 100BASE-TX(诊断)
线对数 1对 2对
速率 100 Mbps 100 Mbps
最大距离 15米(车内够用) 100米
连接器 H-MTD / MATEnet RJ45

2.2 TCP/UDP端口分配——别搞混了

DoIP在传输层用了两个协议:TCP和UDP。它们分工很明确。

UDP端口:13400

这个端口用来做车辆发现路由激活。你想想看,诊断仪刚连上车,还不知道车上有哪些ECU呢。这时候就得靠UDP广播。诊断仪发一个"谁在?"的广播包,车上的DoIP实体收到后,回复自己的IP地址和VIN码。

为什么用UDP?因为它快,无连接,适合这种一问一答的场景。我建议你抓包时重点关注这个端口,很多连接问题都是UDP广播没发出去导致的。

TCP端口:13400

等车辆发现之后,真正的诊断数据交换就走TCP了。诊断仪和ECU之间建立TCP连接,然后通过这个连接发送UDS诊断请求和响应。

TCP保证了数据不丢包、不乱序。你想想看,如果刷写ECU固件时丢了一个包,那整个ECU可能就变砖了。所以诊断数据必须走TCP。

我的小技巧: 端口号13400是ISO 13400标准定义的。你可以在代码里硬编码这个端口,但记得留个配置接口,万一客户要求改端口呢?我在一个项目里就遇到过,客户非要改成13401,说是跟他们的防火墙策略冲突。嗯,灵活一点总没错。

2.3 DoIP报文封装格式——一层套一层

DoIP的报文封装,说白了就是一层套一层。咱们从外往里看。

第一层:以太网帧头

MAC地址、VLAN标签(可选)、以太网类型(0x0800表示IPv4)。

第二层:IP头

源IP、目标IP。车载网络通常用IPv4,地址段比如192.168.0.0/16。

第三层:TCP/UDP头

源端口(随机高位)、目标端口(13400)。

第四层:DoIP头部

这才是DoIP协议的核心。它的结构如下:

+--------+--------+--------+--------+
| 协议版本 | 逆版本  | 负载类型 | 保留字节 |
+--------+--------+--------+--------+
|         负载长度(4字节)           |
+--------+--------+--------+--------+
|         负载数据(可变长度)         |
+--------+--------+--------+--------+

我来解释一下每个字段:

  • 协议版本:1字节。目前是0x02(ISO 13400-2:2019)。
  • 逆版本:1字节。就是版本号取反,比如0xFD。用来做校验,防止版本识别错误。
  • 负载类型:2字节。这个很重要,它告诉接收方"这个包是干嘛的"。比如0x0001是车辆识别请求,0x0004是路由激活请求。
  • 保留字节:2字节。填0x0000。
  • 负载长度:4字节。表示后面负载数据的字节数。
  • 负载数据:可变长度。具体内容由负载类型决定。

注意: 我曾经在调试时发现,某个ECU总是回复"负载类型不支持"。查了半天,发现是逆版本字段算错了。版本号是0x02,逆版本应该是0xFD,结果代码里写成了0xFE。就这一位之差,整个DoIP通信都建立不起来。所以,逆版本一定要用按位取反,别自己手动算

2.4 一个完整的DoIP报文示例

咱们来看一个实际的抓包例子。这是一个车辆识别请求报文:

以太网帧头:
  MAC目标: 01:00:5E:00:00:01 (组播)
  MAC源: 00:1A:2B:3C:4D:5E
  类型: 0x0800 (IPv4)

IP头:
  源IP: 192.168.0.10
  目标IP: 239.192.255.255 (组播)

UDP头:
  源端口: 49152
  目标端口: 13400

DoIP头部:
  协议版本: 0x02
  逆版本: 0xFD
  负载类型: 0x0001 (车辆识别请求)
  保留: 0x0000
  负载长度: 0x00000000 (无额外负载)

你看,这个报文很简单。诊断仪通过UDP组播发出去,车上的ECU收到后,就知道"有人在找我",然后回复自己的信息。

我个人建议你刚开始做DoIP开发时,先学会用Wireshark抓包分析。把上面这个报文结构记在心里,然后对照着抓包数据看。看多了,你自然就熟了。

总结一下:

  • 物理层:车载用100BASE-T1,诊断用100BASE-TX
  • UDP端口13400:车辆发现和路由激活
  • TCP端口13400:诊断数据交换
  • DoIP头部:版本+逆版本+负载类型+长度+负载

下一章咱们会深入聊DoIP的车辆发现机制,包括VIN码的广播和路由激活的完整流程。到时候我会分享一个我在实车测试中遇到的"幽灵ECU"问题,挺有意思的。