这个一般情况下是这样子来设置的:
1.将打开的socket设为非阻塞的,可以用fcntl(socket, F_SETFL, O_NDELAY)完成(有的系统用FNEDLAY也可).
2.发connect调用,这时返回-1,但是errno被设为EINPROGRESS,意即connect仍旧在进行还没有完成.
3.在读套接口描述符集(fd_set rset)和写套接口描述符集(fd_set wset)中将当前套接口置位(用FD_ZERO()、FD_SET()宏),并设置好超时时间(struct timeval *timeout)
4.将打开的socket设进被监视的可写(注意不是可读)文件集合用select进行监视,如果可写,用getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, sizeof(int)); 来得到error的值,如果为零,则connect成功.
select返回0表示connect超时
如果你设置的超时时间大于75秒就没有必要这样做了,因为内核中对connect有超时限制就是75秒。
代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> #include <errno.h> #include <netdb.h> int my_tcp_connect(char *host_name, int port, int *sd, int timeout) { struct addrinfo hints; struct addrinfo *res; int result; char port_str[6]; int flags = 0; fd_set rfds; fd_set wfds; struct timeval tv; int optval; socklen_t optlen; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_INET; hints.ai_socktype = SOCK_STREAM; /* make sure our static port_str is long enough */ if(port > 65535) return -1; snprintf(port_str, sizeof(port_str), "%d", port); result = getaddrinfo(host_name, port_str, &hints, &res); if(result != 0) { /*printf("GETADDRINFO: %s (%s) = %s\n",host_name,port_str,gai_strerror(result));*/ return -1; } /* create a socket */ *sd = socket(res->ai_family, SOCK_STREAM, res->ai_protocol); if(*sd < 0) { freeaddrinfo(res); return -1; } /* make socket non-blocking */ flags = fcntl(*sd, F_GETFL, 0); fcntl(*sd, F_SETFL, flags | O_NONBLOCK); /* attempt to connect */ result = connect(*sd, res->ai_addr, res->ai_addrlen); /* immediately successful connect */ if(result == 0) { result = 1; /*printf("IMMEDIATE SUCCESS\n");*/ } /* connection error */ else if(result < 0 && errno != EINPROGRESS) { result = -1; } /* connection in progress - wait for it... */ else { do { /* set connection timeout */ tv.tv_sec = timeout; tv.tv_usec = 0; FD_ZERO(&wfds); FD_SET(*sd, &wfds); rfds = wfds; /* wait for readiness */ result = select((*sd) + 1, &rfds, &wfds, NULL, &tv); /*printf("SELECT RESULT: %d\n",result);*/ /* timeout */ if(result == 0) { /*printf("TIMEOUT\n");*/ result = -1; break; } /* an error occurred */ if(result < 0 && errno != EINTR) { result = -1; break; } /* got something - check it */ else if(result > 0) { /* get socket options to check for errors */ optlen = sizeof(int); if(getsockopt(*sd, SOL_SOCKET, SO_ERROR, (void *)(&optval), &optlen) < 0) { result = -1; break; } /* an error occurred in the connection */ if(optval != 0) { result = -1; break; } /* the connection was good! */ /* printf("CONNECT SELECT: ERRNO=%s\n",strerror(errno)); printf("CONNECT SELECT: OPTVAL=%s\n",strerror(optval)); */ result = 1; break; } /* some other error occurred */ else { result = -1; break; } } while(1); } freeaddrinfo(res); return result; } int main(int argc, char *argv[]) { char *host_name = "www.baidu.com"; int port = 80; int sd = 0; int timeout = 10; int ret = 0; ret = my_tcp_connect(host_name, port, &sd, timeout); if (ret >= 0) { fprintf(stdout, "OK\n"); } else { fprintf(stdout, "ERROR\n"); } while (1) { sleep(1); } return 0; }