3、DoIP诊断基础回顾:DoIP协议栈(ISO 13400)概述、TCP/UDP传输机制、车辆发现与连接建立
好,咱们进入正题。这一节我打算带大家快速回顾一下DoIP的基础知识。别小看这些基础内容,我在做项目时发现,很多异构网络的坑,其实都源于对DoIP协议栈理解得不够透彻。说白了,你连TCP和UDP在诊断里怎么分工都没搞明白,后面融合CAN诊断时肯定会出乱子。
3.1 DoIP协议栈(ISO 13400)概述
DoIP,全称是Diagnostic over Internet Protocol。它本质上就是把传统的UDS诊断报文,封装到TCP/IP协议栈里,通过以太网传输。ISO 13400这个标准,就是定义了这件事怎么做。
我个人习惯把DoIP协议栈分成四层来看:
- 物理层:就是以太网的物理接口,100BASE-TX或者1000BASE-T。嗯,这里要注意,车载环境通常用BroadR-Reach(现在叫100BASE-T1),一对双绞线就能搞定。
- 传输层:TCP和UDP。TCP负责可靠传输,UDP负责快速发现和通知。
- DoIP层:这是核心。它定义了诊断报文的封装格式、车辆发现机制、连接管理等等。
- 应用层:就是咱们熟悉的UDS诊断服务,比如读取故障码、刷写数据等等。
核心要点:DoIP不是简单地把CAN诊断报文搬到以太网上。它引入了很多新机制,比如车辆发现、路由激活、并发连接管理。这些在CAN诊断里是没有的。
我记得有一次,团队里有个同事直接把CAN诊断的代码逻辑搬到了DoIP上,结果车辆死活发现不了。为什么?因为他没实现DoIP的车辆声明报文。你看,这就是对协议栈理解不到位的问题。
3.2 TCP/UDP传输机制
DoIP里,TCP和UDP的分工非常明确。我经常跟新人说:UDP负责“喊”,TCP负责“聊”。
UDP:用于车辆发现和简单通知
UDP是无连接的,发出去就不管了。DoIP用它来做两件事:
- 车辆发现:诊断仪发一个广播报文,车上的ECU收到后回复自己的IP地址和端口。
- 车辆声明:ECU主动告诉网络“我在这儿”,比如车辆上电时。
你想想看,如果车辆发现也用TCP,那得先建立连接才能知道对方存在,这效率太低了。UDP一发一收,几毫秒就搞定。
TCP:用于诊断数据传输
一旦车辆被发现,诊断仪和ECU之间就要建立TCP连接。所有UDS诊断请求和响应,都通过TCP传输。为什么用TCP?因为诊断数据不能丢,不能乱序。你刷写ECU固件时,丢一个字节都可能变砖。
避坑指南:我曾经遇到过一个问题,诊断仪发了一个长报文,ECU没收到。排查了半天,发现是TCP的Nagle算法在作怪。Nagle算法会把小包合并后再发送,导致诊断响应延迟。解决方案很简单:在socket上设置TCP_NODELAY选项,禁用Nagle算法。
这里我贴一段代码示例,展示如何在Linux环境下设置TCP_NODELAY:
int flag = 1;
if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flag, sizeof(flag)) < 0) {
perror("setsockopt TCP_NODELAY failed");
// 嗯,这里要处理错误
}
3.3 车辆发现与连接建立
这部分是DoIP最有趣的地方,也是和CAN诊断差异最大的地方。CAN诊断里,你直接发请求就行,因为物理上已经连好了。但DoIP不一样,你得先找到车,再建立连接,最后才能发诊断。
车辆发现流程
ISO 13400定义了两种发现方式:
- 主动发现(诊断仪发起):诊断仪发送UDP广播报文(目标端口13400),内容是一个“车辆识别请求”。车上的ECU收到后,回复“车辆识别响应”,包含VIN、IP地址、逻辑地址等信息。
- 被动发现(ECU主动声明):ECU在特定事件(如上电、网络唤醒)发生时,主动发送“车辆声明”报文。这样诊断仪即使没发请求,也能知道有车来了。
我个人习惯在项目初期,两种方式都实现。主动发现用于诊断仪首次连接,被动声明用于车辆状态变化时的通知。你想想看,如果只实现了主动发现,那车辆休眠后重新唤醒,诊断仪就不知道了。
连接建立流程
车辆发现之后,诊断仪和ECU之间需要建立TCP连接。流程如下:
- 步骤1:诊断仪向ECU的IP地址和端口(默认13400)发起TCP三次握手。
- 步骤2:TCP连接建立后,诊断仪发送“路由激活请求”报文。这个报文告诉ECU:“我要开始诊断了,请给我分配一个逻辑地址。”
- 步骤3:ECU验证请求的合法性(比如源IP是否在白名单里),然后回复“路由激活响应”,分配一个逻辑地址给诊断仪。
- 步骤4:路由激活成功后,诊断仪就可以发送UDS诊断请求了。
注意事项:路由激活请求里包含一个“激活类型”字段。我曾经踩过一个坑:测试时用了错误的激活类型,ECU一直拒绝连接。后来查标准才发现,激活类型必须和ECU支持的诊断模式匹配。比如刷写模式需要特定的激活类型,普通诊断用另一种。
这里我整理了一个表格,方便大家对比TCP和UDP在DoIP中的角色:
| 特性 | UDP | TCP |
|---|---|---|
| 用途 | 车辆发现、车辆声明 | 诊断数据传输 |
| 可靠性 | 不可靠,无重传 | 可靠,有重传和确认 |
| 连接 | 无连接 | 面向连接 |
| 典型报文 | 车辆识别请求/响应 | 路由激活、UDS诊断报文 |
| 端口 | 13400(广播) | 13400(默认) |
好了,这一节的内容就到这里。总结一下:DoIP协议栈的核心是TCP和UDP的分工协作,车辆发现靠UDP,诊断传输靠TCP。连接建立时,路由激活是关键一步,千万别搞错激活类型。下一节我们会深入讨论DoIP和CAN诊断的融合策略,到时候会用到这些基础知识。