HP NonStop平台下C语言中带超时限制的setsockopt函数无法正常工作问题求助
解决Tandem-C环境下Socket接收超时设置的问题
针对你遇到的参数冲突警告和超时不生效问题,我们从代码逻辑错误、Tandem环境API差异两个核心方向来逐一解决:
一、先修复致命的逻辑错误
你的代码中setsockopt的分支逻辑完全颠倒了:只有当设置超时失败时才执行send/recv操作,而设置成功时反而跳过了所有数据交互流程!这直接导致超时设置根本没有生效的机会。
修正后的基础逻辑框架
#include <sys/time.h> // 必须包含系统标准头文件,禁止自行定义struct timeval #include <errno.h> // 用于判断超时错误类型 // ... 前面的socket创建、地址初始化代码保持不变 ... if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) { sprintf(RESULTS, "%s","!SENT"); FILE_CLOSE_((short)sockfd); return 0; } // 1. 正确初始化超时结构体(必须同时设置秒和微秒,避免随机值) struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; // 2. 执行超时设置并检查结果 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { sprintf(RESULTS, "SET_TIMEOUT_ERR"); FILE_CLOSE_((short)sockfd); return 0; } // 3. 发送数据 if (send(sockfd, buff, sizeof(buff), 0) < 0) { sprintf(RESULTS, "SEND_ERR"); FILE_CLOSE_((short)sockfd); return 0; } // 4. 接收数据并处理超时 bzero(buff, sizeof(buff)); ssize_t recv_len = recv(sockfd, buff, sizeof(buff), 0); if (recv_len < 0) { // 判断是否为超时错误 if (errno == EAGAIN || errno == EWOULDBLOCK) { sprintf(RESULTS, "TIMEOUT"); } else { sprintf(RESULTS, "RECV_ERR"); } FILE_CLOSE_((short)sockfd); return 0; } else if (recv_len == 0) { // 服务器主动关闭连接 sprintf(RESULTS, "CONN_CLOSED"); FILE_CLOSE_((short)sockfd); return 0; } // 接收成功 sprintf(RESULTS, "SUCCESS"); FILE_CLOSE_((short)sockfd); return 0;
二、解决Tandem-C环境的特定问题
1. 消除"参数冲突"警告
你自行定义了struct timeval,但Tandem系统的标准头文件(如<sys/time.h>)中已经存在该结构体的官方定义,两者的成员类型(比如tv_usec的变量类型)可能存在差异,导致setsockopt的参数类型不匹配,触发警告。
解决方法:删除你自定义的struct timeval代码,改用系统标准头文件提供的定义。
2. 若SO_RCVTIMEO仍不生效:改用select实现超时
部分旧版本的Tandem NonStop TCP/IP环境可能不支持SO_RCVTIMEO选项,此时可以用select系统调用来模拟接收超时,这是更通用的跨平台方案:
#include <sys/select.h> #include <fcntl.h> // ... 连接成功后 ... // 将socket设置为非阻塞模式 int flags = fcntl(sockfd, F_GETFL, 0); if (flags < 0 || fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) { sprintf(RESULTS, "SET_NONBLOCK_ERR"); FILE_CLOSE_((short)sockfd); return 0; } // 发送数据(非阻塞模式下若遇EAGAIN可循环重试,这里简化处理) if (send(sockfd, buff, sizeof(buff), 0) < 0 && errno != EAGAIN) { sprintf(RESULTS, "SEND_ERR"); FILE_CLOSE_((short)sockfd); return 0; } // 使用select等待socket可读,超时5秒 fd_set read_fds; FD_ZERO(&read_fds); FD_SET(sockfd, &read_fds); struct timeval tv = {5, 0}; int select_ret = select(sockfd + 1, &read_fds, NULL, NULL, &tv); if (select_ret < 0) { sprintf(RESULTS, "SELECT_ERR"); FILE_CLOSE_((short)sockfd); return 0; } else if (select_ret == 0) { // 超时触发 sprintf(RESULTS, "TIMEOUT"); FILE_CLOSE_((short)sockfd); return 0; } // 有数据可读,执行接收 bzero(buff, sizeof(buff)); ssize_t recv_len = recv(sockfd, buff, sizeof(buff), 0); // 后续接收结果处理逻辑同前面的修正代码...
三、额外注意事项
- Tandem NonStop系统中,socket相关的错误码可能与标准POSIX略有差异,建议通过
perror打印错误信息,或查阅系统本地手册确认具体错误类型。 - 若仍有疑问,可联系Tandem技术支持,或参考最新的NonStop TCP/IP编程文档确认版本支持的socket选项。
内容的提问来源于stack exchange,提问作者Lavi




