1. 问题概述

在日常使用过程中,我在使用远程控制软件AnyViewer时遇到了连接问题。由于与服务器的连接频繁中断,客户端无法建立稳定的远程控制会话。

从用户角度来看,症状包括:

  • 控制会话无法可靠建立。
  • 连接建立后不久便多次断开。
  • 客户端应用程序报告套接字错误,具体错误代码为 10054 (WSAECONNRESET)。

此错误通常表示连接被对端强制关闭。然而,频繁的断线表明存在超出正常应用层行为之外的更深层次问题。

为了进行调查,我执行了一套系统的调试过程:

  • 审查了客户端网络代码
  • 使用数据包分析工具Unicorn Network Threat Analyzer捕获 TCP 流量
  • 将应用程序错误与网络级行为关联起来

一项关键发现很快浮出水面:

TCP 重置 (RST) 数据包是由客户端自身发送的,而不是由服务器发送的。

这使得调查方向转向了 TCP 内部机制、重传行为和网络可靠性。


2. 数据包捕获的关键观察结果

从捕获的流量数据中,可以发现几个关键模式:

2.1 重复传输相同序列号

服务器反复发送序列号相同的包:

这表明:

服务器认为该数据段未被确认,因此正在不断重传。

2.2 客户端 ACK 停滞

客户始终回复相同的确认编号:

这种行为意味着:

  • 客户端正在等待缺失的片段
  • TCP确认无法继续,因为数据必须按顺序处理。

2.3 大量重传

观察到大量重传现象,证实了这一点:

连接已进入丢包恢复状态

2.4 接收窗口初始状态正常

客户端的接收窗口会一直停留在:

这表明:

  • 客户端未过载。
  • 这个问题并非由应用程序层面的速度缓慢引起。

2.5 最终连接重置 (RST)

最终,客户端发送:

这意味着:

客户端 TCP 协议栈判断连接已无法恢复,并强制终止连接。


3. TCP故障场景的重构

根据现有证据,可以逐步重现此次故障:

第一步:关键数据包丢失

服务器发送:

但这个包裹是:

运输途中丢失或客户拒收

步骤二:乱序数据到达

后续数据包可能成功到达:

然而:

  • TCP 要求按顺序交付
  • 如果没有缺失的片段,客户端无法处理后续片段。

步骤 3:ACK 卡住

客户端反复发送:

这表明:

“我仍在等待缺失的那一段。”

步骤 4:服务器进入重传循环

服务器反复重传:

但客户仍然没有承认这一点。

步骤 5:缓冲区压力和 TCP 死锁

随着越来越多的乱序数据积累:

  • 接收缓冲区开始填充
  • 窗口大小可能会缩小
  • 进展完全停滞

步骤 6:客户端中止连接

在多次失败和超时之后:

Windows TCP 协议栈发送RST消息来终止连接。

4. 根本原因分析

这种行为并非由应用程序逻辑或显式套接字关闭引起,根本原因在于网络层面的数据包传递失败

最可能的原因(≈80%)

丢包加上重传失败

  • 关键部分丢失了
  • 重传也可能失败或延迟。
  • TCP 无法恢复

可能的影响因素

1. 网络不稳定
  • 跨区域延迟(例如,长途路由)
  • 丢包或抖动
  • 拥堵的链路
2. 中间设备
  • NAT网关
  • 防火墙
  • 流量整形或服务质量策略
3. 数据包重新排序
  • 严重的订单错误交付
  • 关键片段缺失导致整个流阻塞
4. 客户端丢包(可能性较小)
  • 校验和错误
  • 窗口验证失败
  • 网卡卸载或驱动程序问题

5. 关键见解

这个案例可以用一条简单的规则来概括:

重复重传相同序列号 + ACK 未收到 = 接收方未接受该数据段

6. 这为何会导致错误 10054

出现错误 10054 的原因是:

  • 客户端 TCP 协议栈检测到无法恢复的传输故障
  • 它使用RST强制重置连接。
  • 应用程序收到此错误信息,提示连接重置错误。

7. 验证步骤

为确认根本原因,建议进行以下检查:

7.1 捕获两端的流量

  • 验证问题序列(185668075)是否到达客户端

7.2 检查重复的 ACK

  • 表示缺失片段

7.3 分析重传模式

  • 快速重传与超时重传

7.4 测试网络质量

  • 丢包(ping)
  • 吞吐量和抖动(iperf)

7.5 禁用网卡卸载(Windows)

  • 大型发送卸载 (LSO)
  • 校验和卸载

8. 结论

问题的根本原因是数据包丢失和恢复失败导致的 TCP 层停滞

关键数据段反复重传但从未得到确认,导致 ACK 停滞、重传循环,最终导致客户端连接重置 (RST)。

9. 工程建议

适用于实时或高吞吐量应用(例如音视频流媒体):

由于存在队头阻塞,TCP 并非理想选择。

考虑:

  • 基于UDP的传输(例如,RTP)
  • 前向纠错(FEC)
  • 自适应比特率控制

如果需要,可以进一步按数据包级别粒度分析此场景,以确定故障是由于真正的丢包还是客户端拒绝造成的

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐