Looyao's Blog

记录一些点滴

C Socket: 关于connect超时设置

| Comments

使用阻塞的socket, 可以设置读写超时, 见下边代码.

1
2
3
4
5
6
7
8
9
10
11
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).

下边是示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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);
}

Comments