C++如何实现带超时的网络连接?(非阻塞socket设置)

来源:网站建设作者:深圳程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《C++如何实现带超时的网络连接?(非阻塞socket设置)》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C++如何实现带超时的网络连接?(非阻塞socket设置)》有用,将其分享出去将是对创作者最好的鼓励。

在C++网络编程场景中,实现带超时的网络连接能够避免程序因远端服务不可达而长时间阻塞,非阻塞socket是实现这一功能的核心基础。通过合理设置socket属性并配合超时检测机制,可以精确控制连接的最大等待时间。

C++如何实现带超时的网络连接?(非阻塞socket设置)

核心实现思路

实现带超时的非阻塞网络连接主要分为四个步骤:首先创建socket并设置为非阻塞模式,然后发起连接请求,接着使用select函数监听socket的可写事件并设置超时时间,最后根据监听结果判断连接是否成功。

具体实现步骤

1. 创建并配置非阻塞socket

首先创建TCP socket,然后通过fcntl函数将socket设置为非阻塞模式,这样调用connect函数时不会阻塞等待连接结果。

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

// 创建并设置非阻塞socket
int create_nonblock_socket(const char* ip, int port) {
    // 创建TCP socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        std::cerr << "socket创建失败: " << strerror(errno) << std::endl;
        return -1;
    }

    // 设置socket为非阻塞模式
    int flags = fcntl(sockfd, F_GETFL, 0);
    if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
        std::cerr << "设置非阻塞模式失败: " << strerror(errno) << std::endl;
        close(sockfd);
        return -1;
    }

    // 配置服务端地址
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    if (inet_pton(AF_INET, ip, &server_addr.sin_addr) <= 0) {
        std::cerr << "IP地址转换失败: " << strerror(errno) << std::endl;
        close(sockfd);
        return -1;
    }

    // 发起非阻塞连接
    int ret = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    // 非阻塞connect返回EINPROGRESS属于正常情况,表示连接正在进行中
    if (ret < 0 && errno != EINPROGRESS) {
        std::cerr << "connect发起失败: " << strerror(errno) << std::endl;
        close(sockfd);
        return -1;
    }

    return sockfd;
}

2. 使用select设置连接超时

非阻塞connect发起后,连接结果不会立即返回,需要通过select监听socket的可写事件,同时设置超时时间,超过设定时间仍未可写则判定连接超时。

// 带超时的连接检测函数,timeout_sec为超时秒数
bool check_connect_timeout(int sockfd, int timeout_sec) {
    fd_set write_fds;
    FD_ZERO(&write_fds);
    FD_SET(sockfd, &write_fds);

    struct timeval timeout;
    timeout.tv_sec = timeout_sec;
    timeout.tv_usec = 0;

    // 监听socket可写事件,设置超时时间
    int ret = select(sockfd + 1, NULL, &write_fds, NULL, &timeout);
    if (ret <= 0) {
        // ret为0表示超时,小于0表示select调用失败
        if (ret == 0) {
            std::cerr << "连接超时" << std::endl;
        } else {
            std::cerr << "select调用失败: " << strerror(errno) << std::endl;
        }
        return false;
    }

    // 检查socket是否真的可写,排除连接错误的情况
    if (FD_ISSET(sockfd, &write_fds)) {
        int error = 0;
        socklen_t len = sizeof(error);
        // 获取socket的错误状态
        if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
            std::cerr << "获取socket错误状态失败: " << strerror(errno) << std::endl;
            return false;
        }
        if (error != 0) {
            std::cerr << "连接失败,错误码: " << error << ", 错误信息: " << strerror(error) << std::endl;
            return false;
        }
        return true;
    }
    return false;
}

3. 完整调用示例

将前面的函数组合起来,就能实现带超时的网络连接功能,调用时可以自定义超时时长。

int main() {
    const char* server_ip = "127.0.0.1";
    int server_port = 8080;
    int timeout = 3; // 超时时间3秒

    int sockfd = create_nonblock_socket(server_ip, server_port);
    if (sockfd < 0) {
        return -1;
    }

    if (check_connect_timeout(sockfd, timeout)) {
        std::cout << "连接成功" << std::endl;
        // 连接成功后可以进行后续数据收发操作
        // ...
    } else {
        std::cout << "连接失败" << std::endl;
    }

    close(sockfd);
    return 0;
}

注意事项

  • 非阻塞socket在连接成功后,如果需要恢复阻塞模式进行数据收发,可以再次调用fcntl去掉O_NONBLOCK标志。
  • select函数的超时时间精度为微秒级,实际超时时间可能存在微小偏差,属于正常现象。
  • 不同系统的非阻塞socket处理逻辑略有差异,Windows平台需要使用ioctlsocket设置非阻塞模式,且错误码定义与Linux不同,需要做兼容处理。
  • 连接超时后需要及时关闭socket,避免资源泄漏。

C++非阻塞socket网络连接超时setsockoptselect修改时间:2026-07-01 17:21:43

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。