2011-11-16 30 views
1

有我做的簡單的套接字程序(服務器/客戶端)。 服務器正在運行的Windows和客戶端是Android應用程序,其中包含由c socket構成的共享庫。getpeername無法識別連接建立

在客戶端,爲了避免凍結,我將套接字更改爲NON_BLOCK,而不是在傳遞connect()函數後回滾到BLOCK套接字。之後,我搜索連接可用getpeername()。

如下...

flags = fcntl(sock, F_GETFL, 0); 
fcntl(sock, F_SETFL, flags|O_NONBLOCK); 

nRet = connect(sock, (struct sockaddr*)&addr, sizeof(addr)); 
if (nRet < 0) 
    if (errno != EINPROGRESS && errno != EWOULDBLOCK) 
     return ERR_CONN; 

... 
... 

nRet = select(sock+1, &readset, &writeset, NULL, &tv); 
if (nRet == 0) 
    if (errno != EINPROGRESS && errno != EWOULDBLOCK) 
     return ERR_SELECT; 

nRet = getpeername(sock, (struct sockaddr*)&addr, &len); 
if (nRet != 0) 
    return ERR_GETPEER; 

fcntl(sock, F_SETFL, flags); 

一切都運作良好。除了在3G模式下工作。

有時即使服務器得到連接,客戶端返回getpeername()中的錯誤。 錯誤代碼是ENOTCONN。

我該如何實施以避免這種情況?任何建議,將不勝感激。 thx提前。


我發現有什麼問題。

首先,我應該在返回之前傳遞connect()之後回滾到BLOCK套接字。第二,似乎select()並不保證爲timeval保留,所以我做了像GetTickCount()的函數,而不是計算時間來打破循環。

這是我的解決方案。

fcntl(O_NONBLOCK); 
connect(); 
fcntl(BLOCK); 

while (true) 
{ 
    fd_set rdfs, wdfs; 
    FD_ZERO(&rdfs); FD_ZERO(&wdfs); 
    FD_SET(sock, &rdfs); FD_SET(sock, &wdfs); 

    tv.tv_sec = 0; tv.tv_usec = 100; 
    nRet = select(sock + 1, &rdfs, &wdfs, NULL, &tv); 
    if (nRet == -1) return -1; 
    else if (nRet) 
    { 
     nRet = getpeername(); 
     if (!nRet) 
      break; 
    } 

    if (get_tick_count() - delay > timeout) 
     return -2; 
} 

thx! sarnold,咖啡館:)

+0

沒有你的'選擇(2)'實際上返回'sock'在' readset'?你的意思是 – sarnold

+0

,我查了FD_ISSET嗎?對不起,我的可憐的英語:(如果是這樣,不,不,我沒有檢查FD_ISSET getpeername之前 – JayMuzie

+0

是的,就是這樣;你應該只嘗試讀出類似於'FD_ISSET(3 )'爲你的'readset'輸出變量。 – sarnold

回答

0

要確定套接字連接,更通常使用getsockopt()而非getpeername()

int so_error; 
socklen_t len = sizeof so_error; 

getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len); 

if (so_error == 0) { 
    /* socket is connected */ 
}