einprogress不是错误,而是非阻塞socket下connect已启动但三次握手未完成的正常状态;需用select/poll监听可写事件,再通过getsockopt获取so_error判断连接终态。

如果您在使用strace跟踪网络程序时发现connect系统调用返回-1且errno显示EINPROGRESS,这通常表明该socket已被显式设置为非阻塞模式,而TCP三次握手尚未完成。以下是针对此现象的多种技术解析与验证路径:
一、确认套接字是否被设为非阻塞模式
该状态的根本前提是套接字处于非阻塞I/O模式。操作系统在非阻塞语境下不会等待连接建立完成,而是立即返回EINPROGRESS作为“操作已启动、尚未就绪”的明确信号。
1、检查代码中是否调用了ioctl(fd, FIONBIO, &on)或fcntl(fd, F_SETFL, O_NONBLOCK)等非阻塞设置函数。
2、在strace输出中搜索fionbio、fcntl或setsockopt系统调用,确认其参数中包含O_NONBLOCK或FIONBIO标志。
3、若未找到上述调用,需核查是否通过第三方库(如libevent、Boost.Asio)隐式启用了非阻塞行为。
二、使用getsockopt读取SO_ERROR选项验证连接终态
仅凭connect返回EINPROGRESS无法判定连接最终成败;必须在后续阶段通过getsockopt获取SO_ERROR值,以区分成功、超时、拒绝等真实结果。
1、在connect返回EINPROGRESS后,使用select、poll或epoll监听该socket的可写事件(而非可读事件)。
2、当可写事件触发时,调用getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &len)读取错误码。
3、若err为0,则连接成功;若err为ECONNREFUSED、ETIMEDOUT、ENETUNREACH等非零值,则对应具体失败原因。
三、通过strace过滤并观察完整连接生命周期
strace默认仅显示系统调用入口与返回,无法直接反映内核后台的TCP状态迁移。需结合事件时序与上下文判断EINPROGRESS是否属于预期流程。
1、执行命令:strace -e trace=connect,select,poll,epoll_wait,getsockopt -f ./your_program,聚焦关键网络调用链。
2、观察connect返回后是否紧随select/poll调用,并检查其timeout参数是否合理(避免无限等待)。
3、确认getsockopt是否在可写事件就绪后被调用,且其返回值是否被正确处理。
四、对比阻塞模式下的strace行为以定位差异
同一段连接逻辑在阻塞与非阻塞模式下strace输出存在本质区别:前者connect会挂起直至完成,后者则立即推进至后续逻辑。
1、临时注释或移除非阻塞设置代码,重新编译运行并用strace捕获connect行为。
2、比较两次输出中connect调用的耗时字段(strace默认显示<...></...>内的微秒数),阻塞模式下该值显著大于0,非阻塞模式下恒为0或极小。
3、若阻塞模式下connect仍返回EINPROGRESS,则需怀疑内核参数异常或socket复用导致的状态污染。
五、检查目标地址可达性与服务端响应能力
EINPROGRESS虽为正常中间态,但若长时间无后续进展(如select永不返回可写),可能指向底层网络或对端问题,而非编程逻辑缺陷。
1、在客户端执行:telnet target_host target_port,观察是否能建立交互式连接。
2、在服务端运行:ss -tlnp | grep target_port,确认监听进程存在且状态为LISTEN。
3、在客户端抓包:tcpdump -i any host target_host and port target_port,验证SYN包是否发出、SYN-ACK是否收到。










