C Socket Connect 超时设置

10 篇文章 0 订阅

Windows 使用 ws2_32.dll

Linux 使用socket相关API

void comm_socket_close(SOCKET fd) {
#ifdef _WIN32
    closesocket(fd);
#else
    close(fd);
#endif
}

/**
 * 连接服务端,含有超时机制
 *
 * @param sock          [in,out] socket结构体
 * @param ipaddr        [in] 连接地址
 * @param port          [in] 端口号
 * @param timeout_sec   [in]超时时间,单位秒(s)
 * @return 1 - 连接成功;-1 - 连接超时
 */
int connect_timeout(SOCKET sock, char *ipaddr, u_short port, long timeout_sec) {
#ifdef _WIN32
    struct sockaddr_in address;
    struct timeval     timeout = {timeout_sec, 0};
    fd_set             setW, setE;
    int                err     = 0;
    int                err_len = sizeof err;

    address.sin_family      = AF_INET;
    address.sin_addr.s_addr = inet_addr(ipaddr);
    address.sin_port        = htons(port);

    // put socked in non-blocking mode...
    u_long block = 1;
    if (ioctlsocket(sock, FIONBIO, &block) == SOCKET_ERROR) {
        comm_socket_close(sock);
        return -1;
    }
    connect(sock, (struct sockaddr *) &address, sizeof(address));

    // connection pending
    FD_ZERO(&setW);
    FD_SET(sock, &setW);
    FD_ZERO(&setE);
    FD_SET(sock, &setE);

    int ret = select(0, NULL, &setW, &setE, &timeout);
    if (ret == 0) {
        printf("Error socket connect timeout\n");
        return -1;
    }
    if (ret < 0) {
        // select() failed or connection timed out
        printf("Error socket connect code (%d)\n", WSAGetLastError());
        comm_socket_close(sock);
        return -1;
    }

    if (FD_ISSET(sock, &setE)) {
        // connection failed
        getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &err_len);
        printf("Error socket connect code (%d)\n", err);
        comm_socket_close(sock);
        return -1;
    }

    // connection successful
    // put socked in blocking mode...
    block = 0;
    if (ioctlsocket(sock, FIONBIO, &block) == SOCKET_ERROR) {
        error_puts("Error socket connect set back block mode.\n");
        comm_socket_close(sock);
        return -1;
    }
    return 1;

#else
    struct sockaddr_in address;
    struct timeval     timeout  = {timeout_sec, 0};
    fd_set             fdset;
    int                so_error = 0;
    int                ret      = 0;
    int                flags;
    socklen_t          len      = sizeof so_error;

    address.sin_family      = AF_INET;
    address.sin_addr.s_addr = inet_addr(ipaddr);
    address.sin_port        = htons(port);

    // 设置Socket为非阻塞模式
    fcntl(sock, F_SETFL, O_NONBLOCK);
    connect(sock, (struct sockaddr *) &address, sizeof(address));

    FD_ZERO(&fdset);
    FD_SET(sock, &fdset);
    ret = select(sock + 1, NULL, &fdset, NULL, &timeout);
    if (ret == 0) {
        error_puts("Error socket connect timeout\n");
        return -1;
    }
    if (ret == -1) {
        printf("Error socket connect %s\n", strerror(errno));
        return -1;
    }
    if (ret == 1) {
        // CONNECTED
        getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len);
        if (so_error != 0) {
            printf("Error socket connect %s\n", strerror(so_error));
            return -1;
        }
    }
    // 设置为阻塞模式
    flags = fcntl(sock, F_GETFL, NULL);
    flags &= (~O_NONBLOCK);
    fcntl(sock, F_SETFL, flags);

    return 1;
#endif
}

参考文献

[1]. stackoverflow . Winsock C++ connect timeout . 2017.09 . https://stackoverflow.com/questions/46045434/winsock-c-connect-timeout
[2]. stackoverflow . C: socket connection timeout . 2020.04 . https://stackoverflow.com/questions/2597608/c-socket-connection-timeout

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值