2011-04-14 60 views
4

我們正在開發一個應用程序,在該應用程序中我們使用基於WinSock的sime套接字方法與外部模塊進行通信。我們的要求是確保連接始終處於打開狀態,因此,每當我們斷開連接時,我們會不斷重試每1分鐘連接一次。追蹤WinSock MFC應用程序中句柄泄漏的來源

我們的問題從這裏開始。我們已經注意到在套接字重新連接的每次重試時,它正好泄漏兩個Windows句柄。我們嘗試了很多選擇,但都沒有工作。哪些手柄可能會泄漏,我們如何才能確定罪魁禍首?

下面是我們使用的是現在的代碼:

bool CSocketClass::ConnectToServer(int nLineNo) 
{ 
string strIPAddress; 
int nPortNo; 
SOCKET* l_ClientSocket; 
int ConnectionResult; 
//---------------------- 
// Create a SOCKET for connecting to server 
if (nLineNo == 1) 
    { 
    m_objLine1.m_ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    strIPAddress = m_objLine1.m_strIPAddress; 
    nPortNo = m_objLine1.m_nPortNo; 
    l_ClientSocket = &(m_objLine1.m_ClientSocket); 
} 
else 
{ 
    m_objLine2.m_ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    strIPAddress = m_objLine2.m_strIPAddress; 
    nPortNo = m_objLine2.m_nPortNo; 
    l_ClientSocket = &(m_objLine2.m_ClientSocket); 
} 
if(INVALID_SOCKET == *l_ClientSocket) 
{ 
    return false; 
} 
//---------------------- 
// The sockaddr_in structure specifies the address family, 
// IP address, and port of the server to be connected to. 
sockaddr_in clientService; 
clientService.sin_family = AF_INET; 
clientService.sin_addr.s_addr = inet_addr(strIPAddress.c_str()); 
clientService.sin_port = htons(nPortNo); 
//---------------------- 
// Connect to server. 
ConnectionResult = connect(*l_ClientSocket, (SOCKADDR*) &clientService, sizeof(clientService)) ; if (ConnectionResult == SOCKET_ERROR) 
{ 
    if (nLineNo == 1) 
    { 
     //ERROR in line1 
    } 
    else 
    { 
     //ERROR in line2 
    } 
    return false; 
} 
else 
//In case of successful connection 
{ 

    //Other actions 
} 
return true; 
} 
+1

您的泄漏不在發佈的代碼中。作爲一個方面說明,不要'closesocket(INVALID_SOCKET)' - 這是毫無意義的,最壞的情況是有害的。 – Erik 2011-04-14 12:58:29

+0

最初,我們只是關閉套接字,只是它的連接,但即使這不是解決我們的目的..你確定泄漏不在這個代碼?因爲我從字面上看過(在調試時)連接語句後,我的代碼完全泄露了2個句柄。爲了確保我說的是windows處理泄漏,我們可以在任務管理器中看到,我不是在談論內存泄漏。 – vrajs5 2011-04-14 13:50:19

+3

@ vrajs5:當你完成這些套接字時,你並沒有關閉這些套接字。當你連接時,這不是泄漏 - 當你忘記清理時它會變成泄漏。 – Erik 2011-04-14 13:55:27

回答

0

我建議你爲了識別內存泄漏和在那裏正在發生的試圖Intel Parallel Inspector

如果您想嘗試下載,請下載試用版。

+0

你說的是內存泄漏檢查器嗎?因爲我正在談論處理泄漏...... – vrajs5 2011-05-01 11:35:04

+0

英特爾Parallel Inspector也能夠檢測泄漏的窗口句柄。我用它來查找泄漏的GDI句柄,我認爲它對於套接字句柄來說是一樣的。 – ronag 2011-05-01 12:17:57

0

查找句柄泄漏的一種簡單方法是記錄所有內容。

每當您獲得句柄時,您獲得的日誌以及有關情況的任何其他詳細信息。每當你釋放一個句柄,記錄你釋放它。包含兩次實際句柄(只是一些十六進制)。

然後你得到一個日誌,看起來像這樣(只是舉例):

Obtained handle 0xf000 (nLineNo = 5) 
Obtained handle 0xb000 (nLineNo = 6) 
Obtained handle 0xd0d0 (nLineNo = 7) 
Released handle 0xf000 
Released handle 0xb000 

通過這個手工採摘,你可以看到你獲得手柄0xd0d0時nLineNo爲7,它從來沒有得到釋放。它並不多,但它確實有幫助,如果情況變得艱難,您甚至可以在每個獲取/發佈版本中嘗試記錄堆棧跟蹤。另外,如果日誌始終可靠地生成,那麼可以根據實際值開始放置斷點(例如,當句柄爲0xd0d0時,在程序中的某一點處中斷,以便您可以看到發生了什麼)。

如果更實用,您可以開始在程序本身中包裝手柄,例如,所有獲得的句柄的std::set以及關於何時獲得的詳細信息,並且您可以有效地開始黑客程序以跟蹤它正在執行的操作(然後在修復它之後撤消所有更改)。

希望有幫助 - 這是我傾向於至少保留所有獲得的所有東西的一部分原因,所以如果最差的情況最糟糕,您可以在關閉時迭代它們並釋放它們(並記錄一個大的「FIX !在這種情況下

m_objLine1.m_ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) 
m_objLine1.m_ClientSocket != INVALID_SOCKET // true 

但是,你無法連接,所以

ConnectionResult = connect(*l_ClientSocket, (SOCKADDR*) &clientService, 
    sizeof(clientService)) 
ConnectionResult == SOCKET_ERROR // true 

,:THIS」消息)

+0

我沒有手動獲取手柄/直接..我只是創建套接字並關閉它..我也記錄打開和關閉事件(它不在這裏的代碼中)但是這並不能解決我們的問題。 – vrajs5 2011-05-01 11:37:47

1

比方說,你正確獲取插座你應該關閉收購套接字句柄:

closesocket(m_objLine1.m_ClientSocket); 

你有兩條線,所以我猜你調用這個函數兩次,一次爲每個行,所以 這就是爲什麼是兩個泄漏手柄。

3

試試微軟提供的免費Process Explorer。它將顯示一個進程的所有打開句柄以及諸如名稱(用於文件,互斥體,事件等句柄)的信息。它還會突出顯示新創建和關閉的句柄,因此如果逐步執行代碼循環並刷新顯示,則可以看到泄露的確切句柄。

+0

+1 Process Explorer很好,另一種選擇是使用sysinternals中的「句柄」工具來檢查哪些句柄已打開 – floyd73 2011-05-06 09:32:52

0

嘗試在closesocket();之後在套接字手柄上添加一個shutdown(SD_BOTH)另外,嘗試添加睡眠約100ms(僅用於測試)並查看結果如何。