connect函数默认是阻塞模式,而且默认超时时间随操作系统而已,各Linux版本之间也不尽相同,大多为几分钟。

要想对connect进行超时处理,就必须按如下步骤:

1. 采用fcntl设置非阻塞式连接以实现connect超时处理;

2. 采用select方法来设置socket connect超时;

3. 采用fcntl将socket设置回阻塞式;

如下是Linux下实现源码:

#include <sys/socket.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <stdio.h>

#include <time.h>

#include <fcntl.h>

#include <errno.h>

int main(int argc, char* argv[])

{

int fd;

int tos = 20; //timeout second

struct sockaddr_in sa;

time_t cur;

if(argc!=3){

printf("%s IP PORTn",argv[0]);

exit(-1);

}

fd=socket(AF_INET, SOCK_STREAM, 0);

if(fd<0){

perror("socket fail");

exit(-1);

}

//select 模型,即设置超时

int ret;

int err;

socklen_t len = sizeof(err);

int flags;

struct timeval timeout;

fd_set rset, wset, exset;

sa.sin_family=AF_INET;

sa.sin_addr.s_addr=inet_addr(argv[1]);

sa.sin_port=htons(atoi(argv[2]));

if(fcntl(fd, F_GETFL, 0) < 0)

perror("fcntl F_GETFL fail");

if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)

perror("fcntl O_NONBLOCK fail");

else

printf("fcntl O_NONBLOCK success.\n");

cur=time(NULL);

printf("before connect: %s", ctime(&cur));

//因为套接字设为NONBLOCK,通常情况下,连接在connect()返回之前是不会建立的,因此它会返回EINPROGRESS错误,如果返回任何其他错误,则要进行错误处理

//if ((ret = connect(fd, (struct sockaddr*)&sa, sizeof(sa))) < 0){

ret = connect(fd, (struct sockaddr*)&sa, sizeof(sa));

cur=time(NULL);

printf("after connect: %s", ctime(&cur));

printf("connect ret=%d, errno=%d.\n", ret, errno);

if(ret < 0){

if(errno != EINPROGRESS) {

printf("errno=%d, EINPROGRESS=%d.\n", errno, EINPROGRESS);

goto DONE;

}

} else

printf("connect success.\n");

//printf("select time=%ds\n", tos);

cur=time(NULL);

printf("before select: %s", ctime(&cur));

FD_ZERO(&rset);

FD_SET(fd, &rset);

wset = rset;

exset = rset;

timeout.tv_sec = tos; //连接超时(秒)

timeout.tv_usec =0;

//select返回值:num 就绪文件数,0:超时,-1:出错

//if((ret = select(fd+1, &rset, &wset, NULL, tos ? &timeout : NULL))

== 0){

//if((ret = select(fd+1, &rset, &wset, &exset, &timeout)) == 0){

ret = select(fd+1, &rset, &wset, &exset, &timeout);

cur=time(NULL);

printf("after select: %s", ctime(&cur));

printf("select ret=%d.\n",ret);

if(ret == 0){

perror("select timeout.\n");

goto DONE;

}else if(ret == -1) {

perror("select error");

goto DONE;

} else{

perror("select success");

//套接字已经准备好

if (FD_ISSET(fd, &rset) || FD_ISSET(fd, &wset)) {

//connect()失败,进行错处理

if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {

//getsockopt()失败,进行错处理

perror("getsockopt err.\n");

}

if(err){

printf("connect err=%d\n", err);

goto DONE;

} else

printf("connect success.\n");

} else {

//connect()失败,进行错处理

printf("select err: socket not set.\n");

}

}

DONE:

//到这里说明connect()正确返回

//下面恢复套接字阻塞状态

if (fcntl(fd, F_SETFL, flags) < 0)

perror("fcntl F_SETFL fail");

else

printf("fcntl O_BLOCK success.\n");

close(fd);

exit(0);

}