C socket: 关于connect超时设置

使用阻塞的socket, 可以设置读写超时,
struct timeval tv_timeout;
tv_timeout.tv_sec = 60;
tv_timeout.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (void *) &tv_timeout, sizeof(struct timeval)) < 0) {
    perror("setsockopt");
}
tv_timeout.tv_sec = 60;
tv_timeout.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv_timeout, sizeof(struct timeval)) < 0) {
    perror("setsockopt");
}

但是这个不会影响connect.
如何设置connect超时呢, 通过信号alarm? 感觉不是一个好的办法.比较好的办法是通过select或者poll判断超时.
首先设置socket fd为非阻塞, connect判断返回值, 如果返回0, 说明connect成功, 如果返回值等于-1并且错误的errno为EINPROGRESS时调用select或者poll判断socket fd的可写状态, 通过select或者poll的超时设置来判断是否超时.
man page是这么写的

EINPROGRESS
The socket is non-blocking and the connection cannot be com-
pleted immediately. It is possible to select(2) or poll(2) for
completion by selecting the socket for writing. After select(2)
indicates writability, use getsockopt(2) to read the SO_ERROR
option at level SOL_SOCKET to determine whether connect() com-
pleted successfully (SO_ERROR is zero) or unsuccessfully
(SO_ERROR is one of the usual error codes listed here, explain-
ing the reason for the failure).

下边是示例代码:

int opt = 1;
//set non-blocking
if (ioctl(sockfd, FIONBIO, &opt) < 0) {
    close(sockfd);
    perror("ioctl");
    exit(0);
}

if (connect(sockfd, (struct sockaddr *) &server_addr, sizeof(struct sockaddr)) == -1) {
    if (errno == EINPROGRESS) {
        int error;
        int len = sizeof(int);
        tv_timeout.tv_sec  = 60; 
        tv_timeout.tv_usec = 0;
        FD_ZERO(&set);
        FD_SET(sockfd, &set);
        if(select(sockfd + 1, NULL, &set, NULL, &tv_timeout) > 0) {
            getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
            if(error != 0) {
                close(sockfd);
                exit(0);
            }
        } else { //timeout or select error
            close(sockfd);
            exit(0);
        }
    } else {
        close(sockfd);
        perror("connect");
        exit(0);
    }
}

opt = 0;
//set blocking
if (ioctl(sockfd, FIONBIO, &opt) < 0) {
    close(sockfd);
    perror("ioctl");
    exit(0);
}


你可能感兴趣的:(C笔记)