
做车载诊断的这几年我最大的感受是诊断通道正从CAN全面转向车载以太网。过去车载诊断的标准流程是诊断仪插OBD口走CAN收发UDS报文一套CANoe脚本就能搞定到了新一代电子电气架构域控制器、智能座舱、自动驾驶相关的ECU都开始挂载车载以太网节点诊断方式变成了DoIPDiagnostic over IP UDS抓包工具也换成了Wireshark。这篇文章不是堆概念而是从我实际做DoIP诊断测试的视角把Wireshark抓包分析TCP/UDS报文的完整过程捋一遍DoIP协议栈怎么分层、TCP和UDP在诊断里分别承担什么活、从车辆发现到路由激活再到UDS响应每一步报文长什么样、以及在项目里踩过的坑怎么排查。适合正在做车载以太网测试、ECU诊断开发或者刚入门想搞懂DoIP报文到底怎么读的朋友。1. 从CAN到车载以太网DoIP到底解决什么问题1.1 传统CAN诊断的瓶颈为什么非要从CAN诊断挪到DoIP一句话CAN不够用了。传统CAN诊断走的是CAN和CAN FD物理层就是OBD口的CAN收发器诊断协议栈是ISO 15765UDS over CAN。CAN的常见速率是500kbpsCAN FD最高能到8Mbps听起来好像还行但真到了整车量产调试、软件刷写、大数据采集场合这个带宽根本顶不住。我举个实际场景给一个域控制器刷写Flash固件固件几十MB很常见。CAN FD一个数据帧撑死也就64字节但刷新流程里并不是每个帧都塞满还要考虑流控、等待时间、传输层分包实际有效吞吐经常打折。用CAN刷这种大固件一次刷写半小时甚至更久一点儿都不夸张。还有一个场景是读DTC快照、冻结帧、环境数据这些数据量动不动几千字节在CAN上要分成几十上百帧去拼解析脚本麻烦传输也慢。再加上现在的车联网远程诊断、OTA刷写、SOME/IP服务化诊断整个方向都在往IP网络迁移CAN诊断这种窄带通道已经被逼到墙角了。还有一个容易被忽视的问题CAN诊断的寻址和路由能力有限。ECU之间的诊断依赖网关路由CAN ID的位宽就11位或29位逻辑地址空间、路由规则都很受限。DoIP这边直接上IP地址和逻辑地址链路天然就是网络化的网关路由、整车组网、跨域诊断都要灵活得多。1.2 DoIP的技术定位与标准体系DoIP对应的标准是ISO 13400中文常叫“道路车辆—基于IP的诊断通信”。与之配合的是ISO 14229也就是UDSUnified Diagnostic ServicesUDS定义了诊断服务的会话层语法和功能比如读DTC、读写数据、安全访问、刷写。DoIP解决了“UDS报文怎么在以太网上传”的问题UDS解决了“诊断内容是什么”的问题。这里要理清一个关键点DoIP并不传输所有诊断数据都走TCP。它把UDP和TCP分得特别清楚。车辆发现、DoIP实体状态查询这类“寻找节点、了解现状”的操作走UDP因为UDP天然支持广播和组播一次发出全网都能收到。真正的UDS诊断消息走TCP因为TCP可靠、有序、长连接能保证诊断命令和响应不错序、不丢包。DoIP的标准端口是13400TCP和UDP都会用到这个端口。很多人第一次看DoIP抓包会懵就是因为没建立起“什么时候用UDP、什么时候用TCP”的概念。记住一句话找车用UDP修车用TCP。后面所有报文分析都绕不开这个思路。1.3 DoIP给诊断工作方式带来的实际改变DoIP上车之后诊断工作方式发生了几个肉眼可见的变化。首先是速度和吞吐量。现在的车载以太网普遍是100BASE-T1起步高端平台开始上1000BASE-T1带宽相对CAN是数量级的提升。刷写固件、读取大量故障数据、标定数据采集时间直接从“小时级”变成“分钟级”产线调试和售后诊断效率提升非常明显。其次是长连接带来了持续诊断的可能。CAN诊断通常是短平快连上、发请求、收响应、断开。DoIP是基于TCP的TCP本身维护连接状态DoIP还有Alive Check保活机制可以让诊断仪和ECU保持稳定长连接持续监控、连续采集、反复读写。这种能力是CAN诊断时代很难做到的。第三是支持远程和整车主网诊断。DoIP跑在IP网络上天然可以和以太网、无线网络、云端平台打通。远程诊断、整车级DTC汇总、OTA升级的所有前置检查和后置验证都可以直接复用IP基础设施。2. 抓包前必须搞懂的三件事协议栈、报文类型与过滤方法2.1 DoIP协议栈的分层结构先建立层次感。一个完整的DoIP诊断报文从网线到Wireshark的呈现经过的层次大概是这样物理层和数据链路层车载以太网常用100BASE-T1或1000BASE-T1物理层采用BroadR-Reach这类技术一对双绞线搞定收发。链路层还是常见以太网帧MAC地址、EtherType。如果是VLAN场景以太网帧里会带802.1Q TagVLAN ID用于细分网络优先级字段用于保证诊断报文的高QoS。网络层IPv4主导部分新平台开始考虑IPv6。DoIP的IP层内容不复杂但要注意分片和TTL等细节。传输层TCP和UDP同时在用。UDP负责车辆发现、状态查询TCP负责路由激活和诊断消息。端口都是13400。应用协议层DoIP头 UDS数据。DoIP头固定8字节控制着整个报文的帧类型、payload长度UDS数据才是真正干活的。在Wireshark里抓到一个包之后面板上会依次展开Ethernet II、IPv4、TCP/UDP、DoIP、UDS如果解析出来。不要一上来就找UDS字节先学会“剥洋葱”一样从底层往上看这样才能定位问题到底出现在哪一层。2.2 DoIP关键报文类型速查DoIP的报文类型通过DoIP头里的Payload Type字段区分两字节。我平时抓包最常遇到的类型就那十几种整理成一个表方便对照Payload Type含义传输层典型场景0x0000Generic DoIP header NACKTCP/UDP协议版本、长度、格式出错时返回0x0001Vehicle Identification RequestUDPTester广播寻找车辆0x0004Vehicle Identification ResponseUDP含VIN、逻辑地址等身份信息0x0005Routing Activation RequestTCPTester向DoIP实体注册0x0006Routing Activation ResponseTCP返回激活结果0x0007Alive Check RequestTCP连接保活检测0x0008Alive Check ResponseTCP保活响应0x8001Diagnostic MessageTCPTCPUDS诊断请求/响应0x8002Diagnostic MessageUDPUDP少数场景使用的UDP诊断0x8003Diagnostic Message AcknowledgementTCP诊断消息被接收确认0x8004Diagnostic Message Negative AckTCP诊断消息被拒绝这里有个地方特别容易困惑诊断消息的Payload Type有时候显示0x8001有时候显示0x4001。我在不同工具、不同Wireshark版本里都见过。实际上这是ISO 13400-2版本演进带来的差异旧版本定义是0x4001到0x4004新版本规范做了调整部分实现使用0x8001系列。遇到这种显示差异不用慌看Wireshark解析出来的DoIP字段或者自己按DoIP头格式手动解析逻辑完全一致。2.3 Wireshark环境准备与抓包基本操作Wireshark的安装本身没什么难度但有几个细节会影响DoIP抓包质量。第一版本尽量选新的4.0以上对DoIP的解析已经做得相当完整可以自动识别DoIP头甚至能把UDS数据解析出来。老版本可能要做一堆手动解析效率差很多。Windows下安装时记得勾选Npcap这是抓包依赖的底层驱动。Linux/Mac下需要确保有权限访问网络接口。第二抓包前选对网卡。连接到车载以太网测试设备后Wireshark主界面会出现对应的网络接口比如USB转以太网适配器、Vector/VN系列、Pico汽车以太网套件等对应接口。选中接口后要确认“启用混杂模式”打开否则可能只能看到发给本机的广播包和组播包单播诊断报文会漏掉。第三过滤策略。抓包过滤器和显示过滤器是两码事很多初学者混着用导致抓包性能很差或者抓到一堆无关数据。如果做DoIP专项抓包抓包过滤直接写tcp port 13400 or udp port 13400这样在链路层就把非13400端口的流量丢掉既减小文件体积又能保护性能。显示过滤则是抓完之后在分析界面上用比如只显示DoIP协议、只显示某个ECU地址的报文后面的实战里我会具体举例。还有一个值得提前做的设置长时间抓包时在“捕获选项”里开启多文件模式比如每个文件100MB环形缓冲覆盖旧文件防止时间和内存被大文件拖垮。这个在做夜间稳定性测试、长时间运行诊断脚本时特别有用。3. 实战全流程拆解从车辆发现到UDS响应3.1 车辆发现阶段UDP上的0x0001与0x0004DoIP诊断的第一步不是直接连TCP而是先在网络里找到设备。Tester会发送一个Vehicle Identification Request也就是0x0001报文目标IP通常是广播地址255.255.255.255或者指定的组播地址UDP端口是13400。这个报文整个网络里的DoIP实体都能收到。请求发出后支持DoIP的ECU或网关会返回Vehicle Identification Response也就是0x0004报文。这个响应里包含非常关键的信息VIN码、DoIP实体的逻辑地址、EID实体的唯一标识、GID组标识等。在Wireshark里看这个报文重点看VIN字段和Logical Address字段VIN能帮你确认当前抓到的是不是目标车辆Logical Address则是后续UDS报文中目标地址的判断依据。还有一种情况是ECU上电后主动发送广播通知报文类型同样是0x0004但没有对应的0x0001请求。这是DoIP实体“主动上线”的宣告Wireshark里看起来就是一个孤立的Vehicle Identification Response别把它当成异常包这正是车辆角色在告诉你“我上线了可以找我做诊断”。3.2 TCP三次握手诊断连接的建立车辆发现做完接下来就是TCP连接。目标IP就是刚才车辆发现阶段拿到的DoIP实体IP目标端口13400。TCP握手的过程大家应该都熟SYN、SYNACK、ACK。但在DoIP场景里我建议大家不要太快划过这个阶段多看几个细节。第一看SYN包里的选项。窗口大小、MSS、SACK许可这些TCP选项能反映当前链路是否存在限制。车载以太网有时跨越网关或经过交换机虽然带宽大但如果有QoS配置、VLAN优先级设置TCP参数也可能受到影响。第二看是否有重传、快速重传、重复ACK、零窗口这类TCP异常。我实际遇到过好几次UDS层面一直超时排查到最后问题根本不在DoIP而是TCP层在一直重传底层链路丢包严重。这个经验真的很重要如果你在Wireshark里看到大量TCP Retransmission先别急着分析UDS内容TCP都穿不过去UDS怎么可能通。第三三次握手完成后TCP进入Established状态后续的DoIP报文都在同一条TCP流里。Wireshark里可以右键任意包选择“追踪TCP流”把整条流的交互顺序看一遍这个操作在分析诊断事务时非常高效。3.3 路由激活Tester向DoIP实体注册TCP连上之后很多人会以为“连上了就能发UDS”但实际不行。DoIP协议里还有一个强制前置步骤路由激活也就是Routing Activation Request类型0x0005。Tester发送0x0005报文里面带着Tester自己的逻辑地址以及激活类型。DoIP实体收到后会判断这个Tester是否合法、是否允许接入然后返回0x0006 Routing Activation Response。这个响应里会包含激活状态码成功、拒绝、未知目标地址、不支持的激活类型等等。只有收到成功的激活响应TCP连接才真正被“授权”用于诊断消息传输。我习惯把路由激活理解成“前台登记”。你进一栋大楼TCP连接只是让你到了门口路由激活才是让你在访客系统里登记身份、拿到临时门禁权限。没登记就去敲部门办公室的门没人会理你。抓包时的表现就是不发路由激活直接发0x8001诊断消息DoIP实体会直接忽略或者给你一个Generic NACKUDS请求毛响应都没有。这里还要注意一个隐蔽细节0x0005路由激活请求里带的Tester逻辑地址在后续所有UDS报文中都必须保持一致。有些测试工具支持配置多个逻辑地址如果配置不当会出现“路由激活用的地址A诊断消息用的地址B”的混乱结果就是ECU侧明明收到了报文却因为地址不对而丢弃。3.4 核心重头戏UDS诊断报文的逐字节解析完成路由激活后终于可以发UDS诊断消息了。我拿一个最典型的场景演示读DTC列表。假设Tester逻辑地址是0x0F00ECU逻辑地址是0x0A01实际地址以厂商诊断规范为准这里只是例子。UDS命令是0x19 02 FF含义是“按状态掩码FF读取DTC”。整条DoIP诊断消息封装如下02 FD 80 01 00 00 00 07 0F 00 0A 01 19 02 FF这段十六进制逐字节拆开是这样的02DoIP协议版本号ISO 13400-2当前版本就是0x02。FD版本反码0x02取反后是0xFD用来校验版本字段是否正确。80 01Payload Type0x8001代表这是TCP上的DoIP诊断消息。00 00 00 07Payload Length4字节大端整数。这里等于7表示后面跟着的payload是7个字节。0F 00Tester的源逻辑地址。0A 01目标ECU的逻辑地址。19 02 FFUDS数据SID是0x19子功能是0x02状态掩码是0xFF。所以DoIP的封装规律很清楚8字节DoIP头之后是2字节源地址、2字节目标地址最后才是真正的UDS数据。不管请求还是响应这个结构都不变只是源地址和目标地址会互换。如果要在自动化脚本里构造这样一个请求核心代码很简单import socket tester_addr 0x0F00 ecu_addr 0x0A01 uds_cmd bytes([0x19, 0x02, 0xFF]) # DoIP payload 源地址 目标地址 UDS数据 payload tester_addr.to_bytes(2, big) ecu_addr.to_bytes(2, big) uds_cmd # DoIP header 版本 反码 PayloadType PayloadLength doip_header bytes([0x02, 0xFD]) (0x8001).to_bytes(2, big) len(payload).to_bytes(4, big) frame doip_header payload s socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((192.168.1.10, 13400)) # 注意实际诊断流程里前面还要先做路由激活这里只演示报文封装 s.send(frame) resp s.recv(4096) print(resp.hex())ECU正确读完这条消息后正响应的UDS部分是以0x59开头0x19 0x40然后是子功能0x02、DTC状态掩码、DTC数量再往后是DTC号和状态字节。整条响应同样被包在正常的DoIP头里。这里要注意DoIP层面可能还会先回一个0x8003诊断消息确认报文表示“我收到了”真正的UDS正响应后面才到。不要把Ack当成UDS响应。如果请求本身有问题ECU回的是负响应UDS部分以0x7F开头结构是7F SID NRC。比如ECU不支持0x19服务会回7F 19 11NRC是0x11表示serviceNotSupported。再比如0x19请求里忘了带状态掩码长度不够可能回7F 19 13NRC 0x13表示报文长度或格式错误。看到7F不要慌先看NRC再回查请求格式。3.5 常见UDS服务与负响应速查做DoIP诊断分析UDS层面的服务不可能绕开。我把自己最常用的服务整理成一个速查表SID服务名典型用途0x10DiagnosticSessionControl切换默认/扩展/编程会话0x22ReadDataByIdentifier按DID读数据0x2EWriteDataByIdentifier按DID写数据0x27SecurityAccess安全解锁刷写/写参数前必备0x19ReadDTCInformation读DTC列表/快照/扩展数据0x14ClearDiagnosticInformation清除DTC0x31RoutineControl例程控制常用作刷写擦除/校验0x34RequestDownload请求下载刷写流程起点0x36TransferData数据传输刷写过程主体0x37RequestTransferExit请求退出传输刷写流程收尾负响应码更是排查问题的关键入口。我遇到的频率从高到低排个序NRC含义常见触发原因0x31requestOutOfRangeDID不存在、参数越界0x22conditionsNotCorrect会话不对、未解锁、前置条件不满足0x13incorrectMessageLengthOrInvalidFormat字节数错、格式错0x33securityAccessDenied没做安全访问解锁0x12subFunctionNotSupported子功能没实现0x11serviceNotSupported服务未实现0x78responsePending处理中不是错误别急着超时0x10generalReject通用拒绝需结合上下文查遇到UDS超时或者NRC异常最忌讳的是“瞎试”。先确认会话状态再确认安全访问状态再确认报文长度和格式最后确认DID/服务是否在当前车型支持。顺序不能乱。4. 常见问题排查与避坑指南4.1 抓不到包或DoIP解析不出来这是新人最常遇到的问题。Wireshark抓了半天只有广播包看不到任何DoIP单播流量或者即使抓到了也是一堆以太网裸数据没被解析成DoIP。先检查硬件和网卡确认你连接的以太网口是真实连通的车载以太网测试口不是Wi-Fi网卡。Wi-Fi网卡在车载以太网诊断场景下基本没用因为抓不到目标单播包或者被AP隔离掉。如果是通过交换机镜像口抓包确认镜像方向是双向的否则只能看到一个方向的报文。再检查混杂模式。Windows下Npcap如果没正确安装或者抓包软件没有以管理员权限运行混杂模式可能无法生效。我踩过最蠢的一次坑就是抓包时忘了开混杂模式单播诊断报文一个都看不到白白排查了一个多小时。如果报文能抓到、但Wireshark没识别成DoIP协议大概率是Wireshark版本太老或者DoIP heuristic解析没有启用。在协议偏好里找到DoIP勾选“Try heuristic subdissector”让Wireshark尝试自动识别DoIP头。另外注意如果诊断流量带了VLAN Tag有些普通PC网卡和抓包驱动会直接丢弃VLAN帧这时候需要换支持VLAN透传的网卡或者在交换机镜像口把Tag处理好再送进来。4.2 TCP连接失败与端口占用TCP连接建立失败最常见的原因是13400端口被其他进程占了。做DoIP测试时测试工具、自己写的脚本、其他诊断软件可能同时抢占这个端口。Windows下查端口占用netstat -ano | findstr 13400Linux下用ss -tlnp | grep 13400找到占用进程后杀掉旧进程或者改掉旧工具的端口配置就能解决。还有一种情况是防火墙拦截了13400端口。Windows防火墙、Linux iptables/firewalld都可能会拦测试时先确认防火墙规则放行了TCP和UDP的13400端口。另外即使TCP端口没被占也可能出现“TCP连上了但DoIP实体没有任何回应”的情况。这时候去看路由激活做了没因为TCP只是通道路由激活才是授权。如果路由激活没完成后续UDS请求直接石沉大海连个NACK都没有。4.3 UDS响应超时与NRC原因定位UDS请求发出后如果一直等不到响应或者收到7F负响应按这个顺序排查最省时间。第一确认报文长度。0x13错误多数是长度问题。比如0x22按DID读数据DID是2字节请求应该是22 DID_High DID_Low如果少写一个字节ECU直接NRC 0x13。第二确认会话状态。很多服务只在扩展会话或编程会话下才支持。默认会话下请求写数据、刷写ECU会回0x22条件不正确。这个层级问题是最常见的尤其是在远程诊断场景Tester连接上来之后默认停在默认会话得先发0x10 03切到扩展会话才能继续操作。第三确认安全访问。需要解锁的服务比如0x2E写数据、0x36传输数据如果没有先做0x27安全访问NRC大概率是0x33。安全访问还要注意算法是否匹配种子和密钥的生成逻辑是OEM或者ECU供应商逼着定错了就继续0x35或0x36。第四确认DID和服务支持范围。请求的DID在目标ECU上不存在NRC是0x31。这个只能靠诊断规范文档逐个核对没有捷径。第五注意0x78。responsePending表示ECU正在处理比如Flash擦除耗时较长ECU会先回一个0x78让Tester不要超时过一会再回真正的正响应或负响应。如果Tester把0x78当成错误处理反而会把一个正常的耗时操作搞成超时失败。4.4 长连接、保活与超时处理DoIP是一个典型的长连接场景。TCP连接建立并完成路由激活后这个连接会一直保持除非有一方主动断开或者长时间无活动。DoIP协议里专门有Alive Check机制。DoIP实体会定期发送0x0007 Alive Check Request要求Tester回应0x0008 Alive Check Response。如果Tester没有及时回应DoIP实体会认为这个Tester已经离线把对应的路由注销后续UDS请求就不处理了。做自动化诊断测试时这个机制特别容易踩坑。脚本如果只是“发请求等响应”长时间不发任何数据连接可能被DoIP实体判定为超时断开。解决办法是在框架里定时处理Alive Check请求确保每次收到0x0007都能自动回0x0008。我在Wireshark里就看到过很多次“Tester一直发UDS但无响应”的案例追到底就是Alive Check没回路由早被注销了。抓包时看Alive Check也很有价值。你可以通过0x0007的频率判断DoIP实体的保活策略如果测试中连接总是莫名断开看看是不是保活响应延迟导致。5. 实测心得与进阶建议5.1 提升Wireshark抓包效率的几个实用技巧做DoIP分析最强调“高效”。分享几个我自己长期在用的技巧。第一自定义列。默认的Wireshark列信息对DoIP分析不够直观。我习惯把doip.payload_type、doip.srcaddr、doip.dstaddr、tcp.stream加进列显示这样一屏就能看出当前报文的帧类型、源地址、目标地址和TCP流编号不用点开每个包。第二善用“追踪TCP流”。右键任意一个诊断报文选择“追踪TCP流”就能看到整条连接上的完整交互TCP握手、路由激活、UDS请求、UDS响应。对单设备调试来说这是最高效的问题定位手段。第三过滤表达式要记几个常用的doip doip.payload_type 0x8001 doip.srcaddr 0x0f00 or doip.dstaddr 0x0f00 tcp.port 13400 tcp.flags.syn 1注意Wireshark显示过滤器里十六进制要写0x8001这样的格式不然容易被当成十进制结果永远匹配不出来。第四长时间抓包一定要用捕获过滤器不要只用显示过滤器。显示过滤器只是“藏起来”抓包流量还是全部进了内存。捕获过滤器在源头就把无关流量丢掉长时间跑稳定性测试时文件小、CPU占用低。第五抓完包先看Expert Info。Wireshark的“Expert Information”面板会汇总所有重传、丢包、错误标记比你在报文列表里肉眼翻高效得多。TCP层的问题在这个面板里一眼就能扫出来。5.2 从DoIP到SOME/IP与SOA诊断的演进DoIP是整个车载以太网诊断的基石但现在的新架构里已经不只是单纯DoIP这么简单了。比如SOME/IPSOME/IP是基于IP的服务中间件很多域控之间的服务发现、服务调用都基于它。诊断服务也可以被封装成SOME/IP服务Tester通过SOME/IP调用诊断服务接口底层再转发为UDS over DoIP或者其他诊断路由。Wireshark对SOME/IP的解析也支持得不错但如果你连DoIP都还搞不清楚看SOME/IP只会更晕。我比较建议的学习路径是先把UDS over DoIP抓包分析练熟把TCP、UDP、逻辑地址、路由激活、DTC读取跑通再去看SOME/IP服务发现、事件通知、远程调用。地基打牢之后上层就是一层窗户纸。5.3 学习路径与工具链推荐接触DoIP诊断你的实验环境至少要能“发真包、抓真包、读真包”。如果公司有VectorVN5640、VN5610这类汽车以太网接口卡配合CANoe的DoIP Option是最省事的方案。Vector工具链对DoIP的支持非常成熟可以直接模拟Tester、自动路由激活、自动处理Alive Check。缺点是贵个人学习阶段很难拿到。如果只是自学入门我更推荐纯软件方案自己写一个简单的Python脚本模拟DoIP Tester在本地或虚拟网卡上连接一个开源DoIP模拟器再用Wireshark抓包。这样虽然看不到物理层和100BASE-T1的细节但DoIP头、TCP握手、路由激活、UDS请求响应这些核心逻辑都能完整走一遍。我自己带新人时经常先让他们用这种方式跑通全流程再上真车台架。另外OLED屏的Pico汽车以太网套件、周立功的部分以太网分析仪也是高性价比的选择支持100BASE-T1抓包和Wireshark接入适合个人和小团队。最后说点个人体会。刚开始做DoIP测试时我最容易犯的错是拿到报文就直接看UDS字节把DoIP头当成冗余信息跳过。后来吃过亏才明白DoIP头里每一个字段都值得看特别是Payload Length和源/目标逻辑地址这些字段一旦不对后面整条链路都会出问题。踩过几次坑之后我现在做DoIP抓包都有一套固定流程先看车辆发现再看TCP握手再看路由激活最后才分析UDS内容虽然慢但稳。这套流程也分享给你。如果大家在实际抓包中遇到奇怪的报文欢迎一起交流我可以把常见现象再整理一份出来。