TCP/IP协议: connect的系统超时控制

来源:互联网 发布:工业信息化软件 编辑:程序博客网 时间:2024/04/30 03:13
 在使用TCP的connect连接服务器时,在默认情况下系统使用的是阻塞式socket,如果服务器当前不可用,则connect会等待直到超时时间到达(大多数伯克利系统将建立一个新连接的最长时间限制为75秒),而这个超时时间是系统内核规定的,并不能使用setSocketOpt来设置,这个函数只能设置send和recv的超时,为了能够随意控制connect的超时时间,可以使用select。大致的过程就是先将socket设置成非阻塞,使用select去轮询套接口,再根据套接口去判断连接状态。
    先看以下代码:
int flag;
flag = fcntl(sock,F_GETFL,0);
flag |= O_NONBLOCK;
fcntl(sock,F_SETFL,flag);//设置非阻塞
if (type == SOCK_STREAM) {
int ret = -1;
connected = connect(sock, (struct sockaddr *) &address, 
sizeof(address));
if (connected != 0 ) {//if 1
if(errno != EINPROGRESS)
logdown(ERROR,"connect error :%s\n",strerror(errno));
else //esle
{
struct timeval tm;
tm.tv_sec = 3;
tm.tv_usec = 0;
fd_set set,rset;
FD_ZERO(&set);
FD_ZERO(&rset);
FD_SET(sock,&set);
FD_SET(sock,&rset);
socklen_t len;
int error = -1;
int res;
res = select(sock+1,&rset,&set,NULL,&tm);
if(res < 0)
{
logdown(WARNNING,"network error in connect\n");
ret =  -1;
}
else if(res == 0)
{
logdown(WARNNING,"connect time out\n");
ret = -2;
}
else if (1 == res)
if(FD_ISSET(sock,&set))
{
flag &= ~O_NONBLOCK;
fcntl(sock,F_SETFL,flag);//设置阻塞
return sock;
}
else
{
ret = -3;
logdown(WARNNING,"other error when select:%s\n",strerror(errno));
}
return ret;
}//else 
}//if 1
return sock;
}
程序先把socket设置成非阻塞,connect在非阻塞模式下会立刻返回,如果没有其他错误,返回值等于0。当connect不能立刻建立连接时,会返回一个EINPROGRESS,表示连接正在建立的过程中,这时我们可以使用select去轮询套接口,而select的轮询超时时间可以根据自己的需要去设置,最主要的是轮询的集合一定要是读和写的集合,即select的第二和第三个参数要赋值,待select返回就可以去判断返回值来确定connect的进程状态了。如果返回值小于0,说明connect的进程出现了错误,如果是等于0则说明connect超时,如果等于1,并且套接口此时的状态是可写,则说明了connect已经成功建立;(设置等待时间,使用select函数等待正在后台连接的connect函数,这里需要说明的是使用select监听socket描述符是否可读或者可写,如果只可写,说明连接成功,可以进行下面的操作。如果描述符既可读又可写,分为两种情况,第一种情况是socket连接出现错误(不要问为什么,这是系统规定的,可读可写时候有可能是connect连接成功后远程主机断开了连接close(socket)),第二种情况是connect连接成功,socket读缓冲区得到了远程主机发送的数据。需要通过connect连接后返回给errno的值来进行判定,或者通过调用 getsockopt(sockfd,SOL_SOCKET,SO_ERROR,&error,&len); 函数返回值来判断是否发生错误)其他情况的话就算是其他错误吧,至此,我们只需要设置select的超时值就可以随心所欲地实现自己想要的connect连接超时了。
    最后,别忘了把套接口设置会阻塞状态,毕竟阻塞状态加线程方便控制。
0 0
原创粉丝点击