4、DoIP传输层:TCP与UDP在DoIP中的角色、DoIP连接管理机制、DoIP流控制与拥塞控制

好,咱们今天聊聊DoIP的传输层。说实话,这一层是整个协议能跑起来的基础。你想想看,没有传输层,诊断数据怎么在网络上安全、可靠地传递?我个人习惯把传输层比作一条高速公路——TCP是走收费车道的专车,UDP则是走应急车道的快马。各有各的活儿,谁也替不了谁。

4.1 TCP与UDP在DoIP中的角色

先说说TCP。DoIP里,TCP主要负责诊断消息的传输。为什么?因为诊断数据要求可靠、有序、不能丢包。你总不希望发一条“读取ECU序列号”的请求,结果ECU收到了“读取ECU序列”,然后回复一堆乱码吧?

我在项目中遇到过一件事。有一次测试,发现诊断会话总是莫名其妙断开。查了半天,原来是TCP的Keep-Alive机制没配好。网关那边觉得连接空闲太久,直接给掐了。嗯,从那以后,我每次做DoIP设计,都会仔细确认TCP Keep-Alive的参数。

TCP在DoIP里的具体角色,我总结了几点:

  • 承载诊断消息:所有UDS诊断请求和响应,都走TCP连接。
  • 保证消息顺序:TCP的序列号和确认机制,确保数据按序到达。
  • 提供可靠传输:丢包重传、流量控制,这些都是TCP的看家本领。

再说UDP。UDP在DoIP里干的是“轻活”——主要处理车辆发现和连接建立前的控制消息。说白了,就是“打招呼”和“问路”用的。

UDP的具体角色:

  • 车辆发现:客户端发一个广播,问“谁在?”,车辆回复“我在,这是我的IP和端口”。
  • 路由激活:在TCP连接建立之前,用UDP完成一些简单的握手。
  • 状态通告:车辆定期广播自己的状态,告诉客户端“我还活着”。

重要区别:TCP是面向连接的,UDP是无连接的。DoIP里,诊断数据必须走TCP,因为丢一个字节都可能造成诊断失败。而UDP消息丢了就丢了,大不了客户端再发一次广播。

4.2 DoIP连接管理机制

连接管理,说白了就是“谁可以连、怎么连、连多久”。DoIP的连接管理比普通TCP连接要复杂一些,因为它要处理多个客户端、多个ECU的情况。

我记得有一次,一个客户问我:“为什么我的诊断仪连上DoIP网关后,过一会儿就断开了?”我一看日志,原来是并发连接数超了。DoIP网关默认只允许4个TCP连接同时存在,第5个一来,直接拒绝。

连接管理的核心机制:

  1. 连接建立:客户端先发UDP广播,找到车辆。然后通过TCP三次握手建立连接。
  2. 路由激活:TCP连接建立后,客户端发路由激活请求,告诉网关“我要诊断哪个ECU”。
  3. 连接维护:网关会定期检查连接状态。如果长时间没有诊断消息,网关会主动断开连接。
  4. 连接终止:客户端或网关都可以主动关闭连接。正常关闭走四次挥手,异常关闭直接发RST。

我的建议:在实际项目中,一定要给连接设置超时时间。我一般设30秒无活动就断开。太短了诊断没做完就被踢,太长了浪费资源。

连接管理还有一个重要概念——逻辑地址。每个ECU在DoIP网络里都有一个唯一的逻辑地址。客户端通过路由激活请求,告诉网关“我要访问逻辑地址0x00E0”。网关负责把诊断消息转发给对应的ECU。

连接状态 描述 超时处理
Listen 等待客户端连接 无超时
Established TCP连接已建立 30秒无活动断开
Activated 路由已激活 按诊断会话超时
Closed 连接已关闭 立即释放资源

4.3 DoIP流控制与拥塞控制

流控制和拥塞控制,这两个词听起来很像,但干的不是一回事。流控制是防止发送方太快,接收方来不及处理。拥塞控制是防止网络太堵,大家都发不出去。

在DoIP里,流控制主要靠TCP的滑动窗口机制。接收方告诉发送方:“我的窗口大小是64KB,你一次别发太多。”发送方就乖乖地按窗口大小发数据。

我曾经踩过一个坑。有一次做DoIP压力测试,同时给网关发大量诊断请求。结果网关直接丢包了。查了半天,发现是网关的接收缓冲区太小,TCP窗口被填满了,但应用层没及时读取。从那以后,我设计DoIP网关时,都会把接收缓冲区设得大一些,至少16KB起步。

拥塞控制呢?DoIP本身没有专门的拥塞控制算法,它依赖TCP的拥塞控制机制。TCP有慢启动、拥塞避免、快速重传和快速恢复这几个阶段。

注意:DoIP的拥塞控制有一个特殊点——诊断消息的优先级。紧急诊断消息(比如安全气囊触发后的诊断)应该优先发送。但TCP本身不区分优先级,所以需要在应用层做处理。我一般会在DoIP消息头里加一个优先级字段,网关根据优先级决定转发顺序。

流控制和拥塞控制的具体实现:

  • 流控制:TCP滑动窗口 + 应用层缓冲区管理。
  • 拥塞控制:TCP的慢启动(初始窗口小,逐渐增大)、拥塞避免(线性增长)、快速重传(收到三个重复ACK立即重传)。
  • DoIP特有机制:诊断消息的流控制帧(如ISO 15765-2中的FC帧),用于控制多帧传输的节奏。

你可能会问:“DoIP不是基于TCP吗?为什么还要流控制帧?”嗯,这里要注意。DoIP的流控制帧是针对诊断协议(UDS)的,不是针对TCP的。UDS消息可能很长,需要分成多个DoIP消息发送。流控制帧就是用来控制这些分片消息的发送节奏的。

举个例子:

// 发送方发送第一个DoIP消息(包含UDS请求的第一帧)
// 接收方回复流控制帧:
//   - BlockSize: 5(每次最多发5帧)
//   - SeparationTime: 10ms(每帧间隔10ms)
// 发送方按这个节奏发送后续帧

这种机制,说白了就是“你发太快了,慢一点”。我在实际项目中,一般把SeparationTime设成5ms到20ms之间。太短了接收方处理不过来,太长了诊断效率太低。

核心要点:DoIP的流控制是两层结构。底层是TCP的流控制,保证网络传输的可靠性。上层是UDS的流控制,保证诊断消息的有序性和完整性。两层缺一不可。

最后,说一个我个人的经验。做DoIP测试时,一定要用网络抓包工具(比如Wireshark)看看TCP窗口的变化。如果窗口经常变成0,说明接收方处理不过来,需要优化应用层代码。如果窗口一直很大但吞吐量上不去,可能是拥塞控制太保守了。

好了,传输层的内容就聊到这儿。下一章咱们讲DoIP的应用层——诊断消息的封装和解析。到时候会涉及更多UDS的内容,做好准备。