直上九天——Dio 触发 RST 排查处理

336 阅读5分钟

引言

我们都知道作为稳定的网络协议 TCP, 在建立稳定的数据传输前需要建立连接,对应在完成传输后将会断开连接状态,关闭连接的正常操作需通过四次握手完成,但当出现异常连接情况时将会通过 RST 进行通道销毁重置。 一二简单介绍 RST 机制与 Dio 框架中 TCP 的调用,三通过一个工作中实际场景排查解决 Dio 触发的 RST 问题

一 RST

  1. RST 包的定义和作用

    • RST(Reset)是 TCP 协议中的一种控制报文段,用于重置 TCP 连接。当一方接收到 RST 报文时,它会立即关闭连接,不需要经过四次握手过程,从而快速且可靠地终止连接。
    • RST 报文通常用于处理异常情况,例如连接中断、连接重置或通信错误等。
  2. RST 包的触发条件

    1. 主动关闭连接方向发送 RST: 当一方(通常是服务器端)主动关闭连接时,如果另一方(通常是客户端)尝试发送数据或继续通信,接收到关闭连接的一方可能会发送 RST 报文,以通知对方连接已经关闭。这种情况下,RST 报文的目的是中断另一方的连接,避免后续的数据传输和通信。

    2. 非法连接请求: 当服务器端接收到一个不合法的连接请求或无效的数据包时,可能会发送 RST 报文作为响应,以拒绝该连接请求并终止连接。这种情况下,RST 报文通常用于防范网络攻击、拒绝未经授权的访问或处理异常情况。

    3. 超时和异常情况: 在 TCP 连接过程中,如果发生超时、网络故障、数据包丢失或其他异常情况,可能会导致连接状态出现不一致或连接无法正常进行。在这种情况下,一方可能会发送 RST 报文,以终止连接并清除连接状态,从而重新建立正常的通信环境。

    4. 连接重置: 当一方尝试使用已经关闭的连接或无效的连接进行通信时,可能会触发连接重置。在这种情况下,接收到无效连接的一方可能会发送 RST 报文,以拒绝该连接请求并通知对方连接已经关闭。

RST 报文通常用于处理异常情况、拒绝无效连接和终止连接,以确保网络通信的安全性、稳定性和可靠性。

二 Dio

Dio 是一个基于 Dart 语言的强大的 HTTP 客户端框架,提供了丰富的功能和灵活的接口,适用于 Flutter、Web 和后端服务的开发。在 Dio 框架中,对网络并发的支持主要体现在以下几个方面:

  1. 异步请求:Dio 支持异步请求处理,可以同时发起多个 HTTP 请求,并发执行,不会阻塞主线程,提高了网络通信的效率。

  2. 连接池管理:Dio 使用连接池管理网络连接,可以重复使用已经建立的连接,避免频繁地创建和销毁连接,减少资源开销和提高性能。

  3. 并发控制:Dio 提供了灵活的并发控制机制,可以通过设置最大并发数、超时时间等参数来控制并发请求的数量和速度,避免因并发过多导致网络拥堵和性能下降。

  4. 错误处理:Dio 提供了丰富的错误处理机制,可以捕获并处理网络请求过程中可能出现的异常情况,包括连接超时、网络错误、服务器错误等,保证了网络通信的稳定性和可靠性。

  5. 数据传输优化:Dio 支持数据压缩、数据缓存等优化技术,可以提高数据传输效率,减少数据传输量,加快数据传输速度。

Dio 框架提供了一系列功能和特性,使得开发者能够方便地进行并发的网络通信,满足各种网络需求,并在网络通信中获得良好的性能和用户体验。

三 问题排查

技术栈为 Flutter 框架集合 dio 插件完成 HTTP 指令下发,服务端未支持长链接机制,即下发需要重新发起 TCP 连接。

业务开发中遇到对设备同一接口短时间频繁请求将出现控制异常现象,且异常均为首条指令生效后出现,设备端分析受控日志发现执行情况正常,需结合抓包分析网络下发过程。

通过抓包发现在快速执行下发操作时候多次出现 RST 通道重置现象,通过对问题包进行数据分析原因均为下发端口与上一次触发 FIN 端口一致导致,即接收端在重复接受重复端口的 TCP 请求时认定这个端口已经是一个处于即将关闭的状态(四次挥手中第三步等待关闭),进行 RST 处理。

客户端(192.0.1.15)                服务器(192.0.1.20)
       |                              |
       |--- 1. [FIN, ACK] 请求关闭连接 ------>|
       |                              |
       |<--- 2. [ACK] 确认收到 [FIN, ACK] ---|
       |                              |      
       |                              |      
       |--- 3. 新的 [SYN] 发起新连接请求 ----> |
       |                              |
       |<--- 4. [RST] 重置连接 --------------|
    


  • 客户端发送 [FIN, ACK] :

    • 客户端(192.0.1.15)发送 [FIN, ACK] 请求关闭连接。
  • 服务器确认 [FIN, ACK] :

    • 服务器(192.0.1.20)发送 [ACK] 确认收到客户端的 [FIN, ACK]。
  • 客户端发起新连接请求:

    • 客户端在关闭连接后,使用相同的端口发送 [SYN] 包发起新的连接请求
  • 服务器重置连接:

    • 服务器接收到相同端口的新的连接请求,认为该端口仍在 TIME_WAIT 状态,因而发送 [RST] 重置连接。

问题涉及到 dio 调用下发,缓存机制导致重复调用端口重复,可通过对请求头每次请求前 Option 重新声明实例化可以避免使用同一内存 Option 对象参数造成请求端口未更新问题,另一说法可在请求中将 option.headers 的 Connection 属性设定为短链接模式可以规避,尚未测试。