分类: LINUX
2013-09-17 10:58:41
原文地址:TCP之控制connect超时 作者:weizhulinux
正确程序:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int fd, retval;
struct sockaddr_in addr;
struct timeval timeo = {3,0};
socklen_t len = sizeof(timeo);
fd_set set;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (argc == 4) timeo.tv_sec = atoi(argv[3]);
int savefl = fcntl(fd,F_GETFL);
fcntl(fd, F_SETFL, savefl | O_NONBLOCK);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));
printf( "%d\n ", time(NULL));
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0){
close(fd);
printf( "connected..1\n ");
return 0;
}
if (errno != EINPROGRESS){
close(fd);
perror( "connect..2 ");
return -1;
}
FD_ZERO(&set);
FD_SET(fd, &set);
retval = select(fd + 1, NULL, &set, NULL, &timeo);
if (retval == -1)
{
close(fd);
perror( "select ");
return -1;
}
else if(retval == 0)
{
close(fd);
fprintf(stderr, "timeout\n ");
printf( "%d\n ", time(NULL));
return 0;
}
if(FD_ISSET (fd,&set))
{
int error = 0;
socklen_t len = sizeof (error);
if(getsockopt(fd, SOL_SOCKET,
SO_ERROR, &error, &len)
< 0)
{
printf ( "getsockopt fail,connected fail\n ");
return -1;
if (error == ETIMEDOUT)
{
printf ( "connected timeout\n ");
}
if(error == ECONNREFUSED)
{
printf( "No one listening on the remote address.\n ");
return -1;
}
}
printf ( "connected .. 3\n ");
fcntl(fd, F_SETFL, savefl);
close (fd);
return 0;
}
有问题的程序:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int fd, retval;
struct sockaddr_in addr;
struct timeval timeo = {3, 0};
socklen_t len = sizeof(timeo);
fd_set set;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (argc == 4) timeo.tv_sec = atoi(argv[3]);
int savefl = fcntl(fd,F_GETFL);
fcntl(fd, F_SETFL, savefl | O_NONBLOCK);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port = htons(atoi(argv[2]));
printf( "%d\n ", time(NULL));
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0)
{
close(fd);
printf( "connected..1\n ");
return 0;
}
if (errno != EINPROGRESS)
{
close(fd);
perror( "connect..2 ");
return -1;
}
FD_ZERO(&set);
FD_SET(fd, &set);
retval = select(fd + 1, NULL, &set, NULL, &timeo);
if (retval == -1)
{
close(fd);
perror( "select ");
return -1;
}
else if(retval == 0)
{
close(fd);
fprintf(stderr, "timeout\n ");
printf( "%d\n ", time(NULL));
return 0;
}
printf( "connected .. 3\n ");
fcntl(fd, F_SETFL,savefl);
close(fd);
return 0;
}
注意:
1.两个程序连远程主机都没问题
2.有问题的程序连本地任何端口都不会报错
3.差别在于好程序比有问题的程序多了一个SO_ERROR的检测,这个检测在man connect中被指定了要检测
EINPROGRESS
The socket is non-blocking and the connection cannot be completed 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() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).