这个一般情况下是这样子来设置的:
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
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}