1.connect函数原型:
|
2.默认情况下,connect函数的超时情况:
引用: http://blog.chinaunix.net/u1/53217/showart_710651.html
《UNP》第一卷 第三版 P85-P86指出伯克利系统的超时时限为75s, Solaris9超时时限为4分钟,所以一般认为是75s到几分钟不等,而我测试的时限为 189s(Linux Kernel 2.6.24),SYN6次重传~~
我的FC8 Linux Kernel 2.6.23.1-42,测试超时时间为 189s
3.支持重试的连接(APUE2 16.4节)
#include < stdio. h>
#include < stdlib. h>
#include < netinet/in . h>
#include < sys/socket. h>
#include < string. h>
#include < fcntl. h>
#define SRV_PORT 65530
#define MAXSLEEP 128
#define errexit( msg) do {perror( msg) ; exit( EXIT_FAILURE) ; } while ( 0)
/* * *
* max sleep time = 1 + 2 + 4 + 8 + 18 + . . . + 64 = 2^7 - 1 = 127 ( s)
* * * /
int connect_retry( int sockfd, const struct sockaddr * srv_addr, socklen_t addrlen)
{
int nsec;
for ( nsec = 1; nsec < = MAXSLEEP; nsec < < = 1)
{
if ( connect( sockfd, srv_addr, addrlen) = = 0)
return 0; /* connection accepted * /
if ( nsec < = MAXSLEEP / 2) /* < = 2^7 /2 = 64* /
sleep ( nsec) ;
}
return - 1
}
int main( int argc, char * argv[ ] )
{
int sockfd;
struct sockaddr_in srv_addr;
socklen_t addrlen;
int flags;
if ( argc ! = 2) {
printf( "Usage: %s <ip>/n" , argv[ 0] ) ;
exit( 1) ;
}
if ( ( sockfd = socket( AF_INET, SOCK_STREAM, 0) ) < 0)
errexit( "socket error" ) ;
addrlen = sizeof ( struct sockaddr) ;
memset( & srv_addr, 0, addrlen) ;
srv_addr. sin_family = AF_INET;
srv_addr. sin_addr. s_addr = inet_addr( argv[ 1] ) ;
srv_addr. sin_port = htons( SRV_PORT) ;
flags = fcntl( sockfd, F_GETFL, 0) ;
fcntl( sockfd, F_SETFL, flags | O_NONBLOCK) ;
printf( "connecting.../n" ) ;
time_t t = time( NULL) ;
//if ( connect( sockfd, ( struct sockaddr * ) & srv_addr, addrlen) < 0) {
if ( connect_retry( sockfd, ( struct sockaddr * ) & srv_addr, addrlen) < 0) {
printf( "interval = %d/n" , time( NULL) - t) ;
close(sockfd);
errexit( "connect error" ) ;
}
close(sockfd);
exit( 0) ;
}
说明:
1. 在阻塞情况下,connect函数在 Linux Kernel 2.6.23.1-42,测试超时时间为 189s。
2. 在用上述方法设置的非阻塞情况下,connect_retry 函数中,如果调用connect失败,进程就会休眠一小段时间然后在尝试连接,每循环一次增加每次尝试的延迟, 直到最大延迟为 127s。