第4章:DoIP报文结构——通用头部格式与常见报文类型
好,咱们进入正题。DoIP报文长什么样?说白了,它就是在标准TCP/IP数据包里面,又套了一层自己的“信封”。这个信封就是通用报文头部。我当年第一次看协议文档时,觉得这东西挺啰嗦,后来调试多了才发现——每个字节都有它的脾气。
4.1 通用DoIP报文头部格式
所有DoIP报文,不管你是诊断请求还是路由激活,都必须带上这个8字节的头部。结构非常固定,我直接给你拆开看:
| 字节偏移 | 字段名 | 长度 | 说明 |
|---|---|---|---|
| 0 | 协议版本号 | 1字节 | 当前标准值为0x02(ISO 13400-2:2012) |
| 1 | 反向协议版本号 | 1字节 | 必须等于0x02,用于版本校验 |
| 2-3 | 负载类型码 | 2字节 | 标识报文的具体用途(见下文) |
| 4-7 | 负载长度 | 4字节 | 后续数据的字节数(不含头部) |
嗯,这里要注意:反向协议版本号这个字段,我见过不少新手踩坑。它必须和协议版本号一致,否则接收方直接丢弃报文。为什么这么设计?其实就是个简单的握手校验,防止版本不匹配的节点乱入。
核心要点:DoIP头部总共8字节,前2字节是版本校验,中间2字节告诉对方“我要干什么”,最后4字节告诉对方“我带了多长的数据”。
4.2 负载类型码详解
类型码是2字节的整型值,范围从0x0000到0xFFFF。ISO 13400-2里定义了几十种,但实际项目中常用的也就那么十几种。我按功能分组给你列出来:
4.2.1 节点管理类
- 0x0001 —— 通用DoIP头部否定确认。说白了就是“你发的东西我不认”,后面会带一个否定码告诉你为啥不认。
- 0x0002 —— 车辆识别请求。诊断仪发这个,ECU就得报上自己的VIN、EID、GID等信息。
- 0x0004 —— 车辆识别响应。ECU回复的车辆信息。
- 0x0005 —— 路由激活请求。这是建立诊断通道的关键一步,我后面会专门讲。
- 0x0006 —— 路由激活响应。ECU告诉你“通道已开”或者“拒绝接入”。
4.2.2 诊断通信类
- 0x8001 —— 诊断消息(UDS over DoIP)。这是最常用的类型,诊断仪发UDS请求就用这个。
- 0x8002 —— 诊断消息确认。ECU收到诊断请求后,先回一个确认包,再回真正的诊断响应。
- 0x8003 —— 诊断消息否定确认。ECU告诉你“诊断消息格式不对”或者“通道没激活”。
4.2.3 连接管理类
- 0x0007 —— 保活请求。诊断仪定期发这个,告诉ECU“我还活着,别关通道”。
- 0x0008 —— 保活响应。ECU回复确认。
- 0x4001 —— 告警事件通知。ECU主动上报一些异常状态,比如电压不稳、温度过高等。
个人经验:我建议你在做DoIP协议栈时,先把0x0001(否定确认)和0x8003(诊断否定确认)这两个类型码的解析逻辑写好。因为调试阶段,90%的报文都是这两个——不是这里错就是那里错。
4.3 负载长度字段的坑
负载长度是4字节,大端序。这个字段我吃过亏。有一次我在项目里发现,诊断仪发过来的报文长度总是对不上,后来抓包一看——负载长度字段写的是0x00000100,但实际后面只跟了200字节数据。ECU按照256字节去解析,直接读到脏数据。
为什么会这样?因为有些开发者在计算长度时,把头部也算进去了。记住:负载长度只包含头部之后的数据,头部本身不算。
避坑指南:我曾经在测试中遇到一个ECU,它收到路由激活请求后,回复的负载长度字段写的是0x00000000,但后面明明跟了4字节的响应数据。结果诊断仪一直收不到有效响应,超时断开连接。后来发现是协议栈里长度计算逻辑写错了——把“无负载”和“负载长度为0”搞混了。
4.4 常见报文类型概览
我把项目中最高频的几种报文类型整理成了一张速查表,你调试时可以直接对照:
| 类型码 | 报文名称 | 方向 | 典型场景 |
|---|---|---|---|
| 0x0002 | 车辆识别请求 | 诊断仪 → ECU | 刚建立TCP连接时,诊断仪先问“你是谁” |
| 0x0004 | 车辆识别响应 | ECU → 诊断仪 | ECU回复VIN、EID等信息 |
| 0x0005 | 路由激活请求 | 诊断仪 → ECU | 识别完成后,申请打开诊断通道 |
| 0x0006 | 路由激活响应 | ECU → 诊断仪 | ECU同意或拒绝激活 |
| 0x8001 | 诊断消息 | 双向 | 真正的UDS诊断请求/响应 |
| 0x0007 | 保活请求 | 诊断仪 → ECU | 每隔几秒发一次,防止通道超时 |
你想想看,整个DoIP通信流程,其实就是这几个报文来回倒腾。先识别,再激活,然后发诊断,最后保活。搞懂了这六种报文,DoIP通信你就掌握了七七八八。
4.5 一个完整的报文示例
光说不练假把式。我给你看一个真实的诊断请求报文,抓包抓到的:
02 02 80 01 00 00 00 05 10 03 00 00 00 00
|--头部--| |--类型--| |----长度----| |--UDS数据--|
拆开来看:
- 02 02 —— 协议版本0x02,反向版本0x02,校验通过。
- 80 01 —— 类型码0x8001,表示这是一个诊断消息。
- 00 00 00 05 —— 负载长度5字节。
- 10 03 00 00 00 00 —— 后面5字节是UDS数据(这里是一个诊断会话控制请求,0x10 0x03)。
注意看,负载长度写的是5,但UDS数据实际占了5字节。完全吻合。如果这里长度写错了,ECU就会解析出问题。
总结一下:DoIP报文头部就是8字节的“身份证”,类型码告诉对方“我要干啥”,负载长度告诉对方“我带了多重的行李”。搞懂这个,你就能看懂所有DoIP报文了。
下一章我会讲路由激活的完整流程,包括激活请求里那些逻辑地址、激活类型到底怎么填。到时候咱们再细聊。