在WinSock MFC应用程序中跟踪句柄泄漏的来源

| 我们正在开发一个应用程序,其中使用基于WinSock的sime套接字方法与外部模块进行通信。我们的要求是确保连接始终保持打开状态,因此,无论何时断开连接,我们都会每1分钟不断尝试重新连接。 我们的问题从这里开始。我们观察到,在每次重试套接字重新连接时,它都会泄漏两个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;
}
    
已邀请:
尝试使用Microsoft提供的免费Process Explorer。它将显示进程的所有打开的句柄以及诸如名称(文件,互斥,事件等句柄)之类的信息。它还将突出显示新创建和关闭的句柄,因此,如果您逐步执行代码循环并刷新显示,则可以看到泄漏的确切句柄。     
假设您正确获取了套接字:
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
在这种情况下,您应该关闭该获取的套接字句柄:
closesocket(m_objLine1.m_ClientSocket);
您有两行,因此我猜您两次调用了此函数,每行一次 这就是为什么两个泄漏的手柄。     
我建议您尝试使用Intel Parallel Inspector来确定内存泄漏及其发生的位置。 如果您想尝试的话,可以下载一个试用版。     
查找句柄泄漏的一种简单方法是记录所有内容。 每次获得句柄时,都要记录获得它的日志以及有关环境的任何其他详细信息。每次释放句柄时,请记录释放它。包括两次实际的手柄(只是一些十六进制)。 然后,您将获得如下所示的日志(仅作为示例):
Obtained handle 0xf000 (nLineNo = 5)
Obtained handle 0xb000 (nLineNo = 6)
Obtained handle 0xd0d0 (nLineNo = 7)
Released handle 0xf000
Released handle 0xb000
手动进行检查,您可以看到在nLineNo为7时获得了句柄0xd0d0,并且从未释放过它。它虽然不多,但确实有帮助,并且如果情况变得艰难,您甚至可以尝试在每个获取/发布版本中记录堆栈跟踪。另外,如果始终以这种方式可靠地生成日志,则可以根据实际值开始放置断点(例如,当句柄为0xd0d0时在程序中的某个点处中断,因此您可以看到发生了什么情况) 。 如果更实用,则可以开始将句柄包装在程序本身中,例如所有获得的句柄中的“ 5”,以及有关何时获得它们的任何详细信息,您可以有效地开始破解您的程序,以跟踪其工作情况(修复该程序后,撤消所有更改)。 希望能有所帮助-这是我倾向于至少保留获得的所有内容的5英镑的部分原因,因此,如果最糟糕的情况变得最糟,您可以在关机时对其进行迭代并释放所有这些(并记录一个大的\“ FIX这条信息!)     
尝试在
closesocket();
之后在套接字句柄上添加
shutdown(SD_BOTH)
。此外,尝试添加约100ms的睡眠(仅用于测试),并观察其运行情况。     

要回复问题请先登录注册