代碼的流程是這樣的
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()也沒有阻塞,也是立即返回的。