简体   繁体   English

C ++ Winsock接受内存泄漏/资源泄漏

[英]C++ Winsock Accept Memory leak/Resource Leak

I have written a small test tcp listener. 我已经编写了一个小型测试TCP侦听器。 Said listener listens over port 28328 and works fantastic, expect for the huge resource/memory leak that happens every single time a client connects to it. 所述侦听器侦听端口28328并工作出色,期望客户端每次连接到该资源/内存时都会发生巨大的泄漏。

#include <stdio.h>

#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")

SOCKET Socket = INVALID_SOCKET;

bool TestServer()
{
    WSADATA wsaData = { 0 };
    if (WSAStartup(MAKEWORD(2, 2), &wsaData))
        return false;

    sockaddr_in addr = { 0 };

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    int Enable = 1;
    setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&Enable, sizeof(int));

    addr.sin_family = AF_INET;
    addr.sin_port = htons(28328);
    addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(Socket, (sockaddr*)&addr, sizeof(sockaddr)))
        return false;

    if (listen(Socket, 50))
        return false;

    return true;
}


void Dolisten()
{
    if (TestServer())
    {
        sockaddr_in addr = { 0 };

        SOCKET Client_Socket = 0;

        int Lenght = sizeof(addr);

        for (;;)
        {
            Client_Socket = INVALID_SOCKET;

            Client_Socket = accept(Socket, (struct sockaddr *)&addr, &Lenght);

            if (Client_Socket == INVALID_SOCKET)
                continue;

            printf("Client Connected %X\n", Client_Socket);

            shutdown(Client_Socket, 2);
            closesocket(Client_Socket);
        }
    }
}


int main(int argc, char* argv[])
{
    Dolisten();

    WSACleanup();

    return 0;
}

While the original listener is much bigger than this and probably has a lot more problems which I haven't gotten to yet, as of right now this my biggest issue. 虽然原始的侦听器比这个更大,并且可能还有很多我还没有解决的问题,但到目前为止,这是我最大的问题。

I assume that the issue occurs as a result of accepting of the socket and it not closing properly which then leaks to a handle leak. 我认为问题是由于接受套接字而导致的,并且没有正确关闭,然后泄漏到手柄泄漏。 I base this on the fact that when I looked at task manager and other tools that monitor a process I can see the handle count increasing at the same rate as my connection happen. 我基于这样一个事实,当我查看任务管理器和其他监视进程的工具时,可以看到句柄数以与连接发生时相同的速率增加。

Note: 注意:

1) By the looks of it the leak happens on the Non-Paged Memory. 1)从外观上看,泄漏发生在非分页内存上。

2) This same snippet of code if compiled and used in a linux environment will not yield the same memory/resource leak. 2)如果在Linux环境中编译和使用相同的代码片段,则不会产生相同的内存/资源泄漏。

3) I have compiled and tested this code on multiple windows machines and the same problem occurs. 3)我已经在多台Windows机器上编译并测试了此代码,并且发生相同的问题。

4) (EDIT) I did see a couple of people with this exact problem posting on some of the MSDN forums and VS forums but all they were told to do was submit a ticket. 4)(编辑)我确实在几个MSDN论坛和VS论坛上看到几个有这个确切问题的人,但是他们被告知要做的只是提交一张票。

The non-paged-pool is a kernel resource, and relates to memory which can not be paged by the operating system, and is a scarce resource. 非分页池是内核资源,它与操作系统无法分页的内存有关,是一种稀缺资源。 So keeping an eye on it, is a good thing. 因此,关注它是一件好事。

The fact it is in kernel, means the memory is not directly in your control. 它位于内核中,这意味着内存并不直接在您的控件中。 It may be that the memory relates to un-sent, un-processed packets, which case the resource is the responsibility of your program indirectly. 内存可能与未发送,未处理的数据包有关,在这种情况下,资源是程序的间接责任。

Check for the handle leak - where that is coming from. 检查手柄泄漏-泄漏来自何处。 Application Verifier Microsoft : Application Verifier download can help identify the call stacks which are leaking memory and handles. 应用程序验证程序Microsoft:下载应用程序验证程序可以帮助识别正在泄漏内存和句柄的调用堆栈。

There's no memory leak in the application you have shown. 您显示的应用程序中没有内存泄漏。

Due to the way TCP/IP works, resources associated with closed connections can not be freed immediately. 由于TCP / IP的工作方式,与封闭连接关联的资源无法立即释放。 Packets may arrive out of order or be retransmitted after the connection has been closed. 连接关闭后,数据包可能会乱序到达或重新发送。 So even after a call to closesocket the actual OS socket remains open for a predefined amount of time (usually 2-3 minutes, can be adjusted with TcpTimedWaitDelay). 因此,即使在调用closesocket ,实际的OS套接字仍会在预定义的时间段内保持打开状态(通常为2-3分钟,可以使用TcpTimedWaitDelay进行调整)。

If you run netstat -an , you'll see a bunch of connections in CLOSE_WAIT or TIME_WAIT state: 如果运行netstat -an ,则会看到一堆处于CLOSE_WAIT或TIME_WAIT状态的连接:

  TCP    127.0.0.1:28328        127.0.0.1:56508        TIME_WAIT
  TCP    127.0.0.1:28328        127.0.0.1:56510        TIME_WAIT
  TCP    127.0.0.1:28328        127.0.0.1:56512        TIME_WAIT
  TCP    127.0.0.1:28328        127.0.0.1:56514        TIME_WAIT
  TCP    127.0.0.1:28328        127.0.0.1:56516        TIME_WAIT
  . . .

Of course (kernel) memory is needed to store these temporary states. 当然,需要(内核)内存来存储这些临时状态。

In addition, the TCP port number from the ephemeral range cannot be reused immediately, which means the rate at which you can open/close connections is quite limited. 此外,临时范围内的TCP端口号无法立即重用,这意味着打开/关闭连接的速率非常有限。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM