You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Winsock阻塞socket send()返回WSAETIMEDOUT(10060)问题排查咨询

Winsock阻塞Socket send()返回WSAETIMEDOUT(10060)的TCP层面分析与问题解答

你的代码实现模式如下:

auto result = ::send(...);
if (result == SOCKET_ERROR)
{
  auto err = ::WSAGetLastError();
  // err can be WSAETIMEDOUT
}

以下针对你的疑问和场景逐一解答:

核心疑问解答

1. WSAETIMEDOUT是否仅在设置SO_SNDTIMEO选项时才会出现?

不是。SO_SNDTIMEO控制的是send()调用等待写入内核发送缓冲区的超时,但TCP协议层面的连接失效(比如重传次数耗尽)也会触发WSAETIMEDOUT,这种情况和SO_SNDTIMEO完全无关。

2. SO_SNDTIMEO默认值为0(永不超时),是否意味着失败的send()会永久阻塞?Windows是否有内置硬编码超时?

SO_SNDTIMEO为0时,send()会一直阻塞直到数据能写入内核缓冲区,或者TCP连接被判定失效。Windows没有针对send()阻塞的硬编码超时,但TCP协议栈本身有重传超时机制:当未收到ACK的数据包重传次数耗尽后,内核会终止连接,此时阻塞的send()会被唤醒并返回WSAETIMEDOUT。

3. TCP重传机制在此场景下如何作用?若所有重传尝试失败,连接会停滞还是会触发WSAETIMEDOUT(与SO_SNDTIMEO无关)?

TCP发送端会维护未被ACK的数据包(存储在内核发送缓冲区),当超时未收到ACK时启动重传,重传间隔会指数级增长(从几百毫秒逐步延长到几秒)。当重传次数达到系统预设阈值(Windows默认通常为5次左右,可通过注册表调整),TCP栈会判定连接已失效,主动关闭连接并唤醒所有阻塞在该socket上的操作(包括send()),返回WSAETIMEDOUT错误,不会让连接一直停滞。

关于send()返回WSAETIMEDOUT的假设是否正确?

你的理解部分正确,但需要补充:
当内核发送缓冲区被未收到ACK的旧数据占满时,send()会阻塞等待缓冲区空闲。如果此时TCP重传耗尽导致连接失效,send()会返回WSAETIMEDOUT;但如果只是缓冲区满但连接仍正常,send()会一直阻塞直到缓冲区有空间(除非设置了SO_SNDTIMEO超时)。
另外,即使数据已经写入内核缓冲区,后续TCP重传失败导致连接中断,后续的send()调用也可能返回WSAETIMEDOUT。

其他可能的原因

除你提到的中间路由器丢包、网络断开、接收端异常外,还有以下情况:

  • 发送端主机的网络栈故障(如TCP协议栈异常、网卡驱动问题)
  • 网络链路严重拥塞,数据包延迟超过TCP重传阈值
  • 防火墙或入侵检测系统(IDS/IPS)主动丢弃TCP数据包或ACK包
  • 路由路径变更,原有连接的数据包无法到达对端,触发重传超时

接收端可能存在的问题

接收端的这些情况会间接导致发送端send()返回WSAETIMEDOUT:

  • 接收端应用挂起或崩溃,停止读取socket接收缓冲区,导致接收缓冲区满。此时TCP滑动窗口会缩小到0,发送端无法继续发送数据,内核发送缓冲区被占满,send()进入阻塞状态。若长时间没有窗口更新,TCP重传耗尽后会触发WSAETIMEDOUT。
  • 接收端TCP栈异常,无法正常生成ACK包,导致发送端一直重传直到超时。
  • 接收端主机资源耗尽(如CPU、内存占满),无法处理TCP数据包,导致ACK无法及时发送。

内容的提问来源于stack exchange,提问作者rnd_nr_gen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 12:57:26