You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动