代码的流程是这样的
1 建立一个socket
2 设置socket为非阻塞
3 connect
4 把socket放到一个fd_set中
5 select 这个socket,监视可写事件
6 判断是否超时或者连接成功
代码如下---------------------------------------------------------------------
struct sockaddr_in servAddr;
servAddr.sin_port = htons(port);
servAddr.sin_family = AF_INET;
inet_aton(servIp,&servAddr.sin_addr);
//设置socket为非阻塞
unsigned long ul = 1;
int rm = ioctl(this->m_socket,FIONBIO,&ul);
if(rm == -1)
{
//ioctl failed
return -1;
}
if(connect(this->m_socket,(sockaddr*)&servAddr,sizeof(sockaddr)) == 0)
{
//connect success
return 0;
}
if(errno != EINPROGRESS)
{
return -1;
}
log_debug("%s",strerror(errno));
//检测socket是否可写
fd_set writeSet,readSet;
FD_ZERO(&writeSet);
FD_SET(this->m_socket,&writeSet);
int num = select(this->m_socket+1, NULL, &writeSet,NULL,tv);
if(num > 0)
{
if(FD_ISSET(this->m_socket,&writeSet))
{
//设置socket为阻塞
ul = 0;
ioctl(this->m_socket,FIONBIO,&ul);
return 0;
}
}
首先说一下这段代码的执行结果:当连接一个并不存在的socket时,select总是返回连接成功
按照这个流程,这段代码的依据就是当非阻塞时,connect立刻返回-1,同时errno设置为EINPROGRESS。然后再检测socket是否可写,如果可写了,说明socket已经建立的连接,这个时候select的会在write fd_set中把socektfd置位,同时返回,这个时候判断select的返回值和用FD_ISSET宏来判断是否socketfd是否已经被置位来判断是否连接成功。注意:所有的这一切都是建立在 “如果一个socket建立了连接,那么这个socket是可写的”,这看起来没有错,但是关键是,如果连接不成功,select是否会判断socket为可写的呢?我们知道,当连接被关闭时,select仍然判断socket是可读的。难道即使socket连接不成功,select仍然返回
可写吗?经过试验,真的是这样的。所以,上面的代码如果在异常情况下仍然正常工作,在select返回时须作如下修改:
if(FD_ISSET(this->m_socket,&writeSet))
{
int error = 0;
int errLen = sizeof(error);
if(getsockopt(this->m_socket,SOL_SOCKET,SO_ERROR,&error,(socklen_t*)&errLen) < 0)
{
return -1;
}
if(error != 0)
{//当error等于0的时候才说明连接成功
return -1;
}
//设置socket为阻塞
ul = 0;
ioctl(this->m_socket,FIONBIO,&ul);
return 0;
}
//以上的代码中的思想我正在用,但真的没起到连接超时的效果,一旦连接不成功还是回立即返回的.还有socket在阻塞的情况下,connect()也没有阻塞,也是立即返回的。
希望有这方面经验的朋友多多参与交流,共同提高