非阻塞模式下服务端accept()成功但客户端connect()报10035错误
问题成因
Windows平台下非阻塞Socket调用connect()返回的错误码10035对应常量WSAEWOULDBLOCK,该返回值不是连接失败的标识,而是非阻塞模式下的正常状态提示,这是你遇到该故障的核心原因。
非阻塞模式的Socket不会像阻塞模式那样,等待TCP三次握手全部完成后才从connect()调用返回。由于三次握手本身需要网络交互耗时,系统无法瞬间完成连接操作,会立刻返回10035告知调用方:连接操作正在后台执行,当前无法立刻完成。
你当前的客户端逻辑把这个返回值直接判定为连接失败,随即关闭Socket重试,直接打断了正在进行的三次握手流程。哪怕服务端已经完成accept()调用,客户端侧的旧连接已经被主动释放,新发起的重试连接又会立刻返回10035,最终形成“服务端显示接收到连接、客户端始终提示连接失败”的现象。
另外结合你提到的客户端、服务端均为数据包嗅探器的场景,还要排除一种特殊情况:如果嗅探器通过WinPcap/Npcap等驱动直接接管了网卡流量,且过滤规则没有放行自身Socket连接的TCP握手包,会导致操作系统协议栈收不到对端返回的SYN-ACK报文,连接始终无法完成握手,也会持续返回10035。
解决方法
- 修正非阻塞
connect()的错误判定逻辑:不要将返回10035作为连接失败的判断依据。只有当connect()返回WSAECONNREFUSED(连接被拒绝)、WSAENETUNREACH(网络不可达)、WSAEADDRNOTAVAIL(地址不可用)这类明确的失败错误时,才需要关闭Socket发起重连。 - 用IO多路复用机制检测连接完成状态:发起
connect()调用收到10035返回后,将当前Socket加入多路复用(select/WSAWaitForMultipleEvents/epoll,根据你用的网络模型选择)的可写事件监听集合,设置合理的超时时间:- 若监听到Socket触发可写事件,调用
getsockopt()读取Socket级别的错误码,错误码为0即代表三次握手完成、连接成功,可以进入正常的数据收发流程 - 若等待超时,或者读取到的错误码为明确的连接失败类型,再关闭当前Socket执行重连逻辑
- 若监听到Socket触发可写事件,调用
- 嗅探器场景规则适配:在嗅探器的流量过滤规则中,补充跳过当前程序用于进程间通信的端口对应的TCP流量,不要拦截、篡改自身Socket连接的握手包与正常通信包,避免操作系统协议栈无法正常完成连接流程。
内容的提问来源于stack exchange,提问作者Chirag Arora
相关产品推荐
相关产品推荐

