1

Я пишу прокси-сервер tcp и, хотя он работает, он оставляет утечку памяти. Я манипулировал кодом для пересылки входящего пакета самому себе, чтобы создать 10000 сокетов и закрыть их, чтобы увидеть, где находится утечка. Однако я не могу понять это. Я использовал deleaker, и он не показывает никаких утечек (кроме небольшого, что мне все равно.) http://i.imgur.com/7r6u4Jd.pngУтечка памяти на сокете

Но тогда я отключаю две коробки, и это выходит. enter image description here

Любая помощь будет оценена по достоинству!

Код:

#include <winsock2.h> 
#include <stdio.h> 
#include <windows.h> 
#include <ws2tcpip.h> 
#include <tchar.h> 
#include <process.h> /* _beginthread() */ 

// Need to link with Ws2_32.lib 
#pragma comment(lib, "Ws2_32.lib") 

#define PORT "1234" /* Port to listen on */ 
#define BUF_SIZE 4096 /* Buffer for transfers */ 

typedef struct { 

    char *host; 
    char *port; 
    SOCKET sock; 

} 
HandleStruct; 

unsigned int S2C(SOCKET from, SOCKET to) 
{ 

    char buf[BUF_SIZE]; 
    unsigned int disconnected = 0; 
    size_t bytes_read, bytes_written; 
    bytes_read = recv(from, buf, BUF_SIZE, 0); 
    if (bytes_read == 0) { 

     disconnected = 1; 

    } 

    else { 

     bytes_written = send(to, buf, bytes_read, 0); 
     if (bytes_written == -1) { 

      disconnected = 1; 

     } 


    } 

    return disconnected; 

} 

unsigned int C2S(SOCKET from, SOCKET to) 
{ 

    char buf[BUF_SIZE]; 
    unsigned int disconnected = 0; 
    size_t bytes_read, bytes_written; 
    bytes_read = recv(from, buf, BUF_SIZE, 0); 
    if (bytes_read == 0) { 

     disconnected = 1; 

    } 

    else { 

     bytes_written = send(to, buf, bytes_read, 0); 
     if (bytes_written == -1) { 

      disconnected = 1; 

     } 


    } 

    return disconnected; 

} 

void handle(void *param) 
{ 

    HandleStruct *args = (HandleStruct*) param; 
    SOCKET client = args->sock; 
    const char *host = args->host; 
    const char *port = args->port; 
    SOCKET server = -1; 
    unsigned int disconnected = 0; 
    fd_set set; 
    unsigned int max_sock; 
    struct addrinfo *res = NULL; 
    struct addrinfo *ptr = NULL; 
    struct addrinfo hints; 
    /* Get the address info */ 
    ZeroMemory(&hints, sizeof(hints)); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_protocol = IPPROTO_TCP; 
    if (getaddrinfo(host, port, &hints, &res) != 0) { 

     perror("getaddrinfo"); 
     closesocket(client); 
     return; 

    } 

    /* Create the socket */ 
    server = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 
    if (server == INVALID_SOCKET) { 

     perror("socket"); 
     closesocket(client); 
     return; 

    } 

    /* Connect to the host */ 
    if (connect(server, res->ai_addr, res->ai_addrlen) == -1) { 

     perror("connect"); 
     closesocket(client); 
     return; 

    } 

    if (client > server) { 

     max_sock = client; 

    } 

    else { 

     max_sock = server; 

    } 

    /* Main transfer loop */ 
    while (!disconnected) { 

     FD_ZERO(&set); 
     FD_SET(client, &set); 
     FD_SET(server, &set); 
     if (select(max_sock + 1, &set, NULL, NULL, NULL) == SOCKET_ERROR) { 

      perror("select"); 
      break; 

     } 

     if (FD_ISSET(client, &set)) { 

      disconnected = C2S(client, server); 

     } 

     if (FD_ISSET(server, &set)) { 

      disconnected = S2C(server, client); 

     } 


    } 

    closesocket(server); 
    closesocket(client); 
fprintf(stderr, "Sockets Closed: %d/%d", server, client); 
    _endthread(); 
    return; 

} 

int _tmain(int argc) 
{ 

    WORD wVersion = MAKEWORD(2, 2); 
    WSADATA wsaData; 
    int iResult; 
    SOCKET sock; 
    struct addrinfo hints, *res; 
    int reuseaddr = 1; /* True */ 
    /* Initialise Winsock */ 
    if (iResult = (WSAStartup(wVersion, &wsaData)) != 0) { 

     fprintf(stderr, "WSAStartup failed: %dn", iResult); 
     return 1; 

    } 

    char * host = "127.0.0.1"; 
    char * port = "1234"; 

    /* Get the address info */ 
    ZeroMemory(&hints, sizeof hints); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    if (getaddrinfo(NULL, PORT, &hints, &res) != 0) { 

     perror("getaddrinfo"); 
     WSACleanup(); 
     return 1; 

    } 

    /* Create the socket */ 
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 
    if (sock == INVALID_SOCKET) { 

     perror("socket"); 
     WSACleanup(); 
     return 1; 

    } 

    /* Enable the socket to reuse the address */ 
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, 
    sizeof(int)) == SOCKET_ERROR) { 

     perror("setsockopt"); 
     WSACleanup(); 
     return 1; 

    } 

    /* Bind to the address */ 
    if (bind(sock, res->ai_addr, res->ai_addrlen) == SOCKET_ERROR) { 

     perror("bind"); 
     WSACleanup(); 
     return 1; 

    } 

    /* Listen */ 
    if (listen(sock, 6500) == SOCKET_ERROR) { 

     perror("listen"); 
     WSACleanup(); 
     return 1; 

    } 

    freeaddrinfo(res); 
    int i = 0; 

    HandleStruct *arg; 
    arg = (HandleStruct *)malloc(sizeof(HandleStruct)); 
/* Main loop */ 
    while(1) { 

     int size = sizeof(struct sockaddr); 
     struct sockaddr_in their_addr; 
     SOCKET newsock; 
     ZeroMemory(&their_addr, sizeof (struct sockaddr)); 
     newsock = accept(sock, (struct sockaddr*)&their_addr, &size); 

     if (newsock == INVALID_SOCKET) { 

      perror("acceptn"); 

     } 
     else { 

      arg->sock = newsock; 
      arg->host = host; 
      arg->port = port; 

      if (i < 10000) { 
       _beginthread(handle, 0, (void*) arg); 
       i++; 
      } 
     } 
    } 

    closesocket(sock); 
    WSACleanup(); 
    return 0; 

} 

ответ

1

Я не знаком с чтением программы в скриншотах вы вывешенные; Однако, вероятно, вы должны быть обеспокоены этой линией:

arg = (HandleStruct *)malloc(sizeof(HandleStruct)); 

Здесь вы выделение памяти для через malloc(), который не кажется, быть очищен в любом месте с последующим вызовом free(). Вы передаете arg в handle(), но все равно не освобождаете память.

Это не появляются быть handle() «s ответственность очистить arg, так что вы должны, вероятно, вызов free() после цикла while, или вы могли бы выделить в начале каждого цикла и DEALLOCATE это в конце.

Или вы могли бы избавить себя от хлопот и использовать std::unique_ptr, и при необходимости изменить свои темы для std::thread, который само-документы, которые принадлежат корпорации ЦЭТ памяти:

void handle(std::unique_ptr<HandleStruct> args) 
{ 
    // Manipulate args 
    ... 
} 

int main() 
{ 
    std::unique_ptr<HandleStruct> pHandle = std::make_unique<HandleStruct>(); 
    for (;;) 
    { 
     ... 
     pHandle->sock = newsock; 
     pHandle->host = host; 
     pHandle->port = port; 
     // Create thread: 
     std::thread t(&handle, pHandle); 
     // Wait for thread to finish so pHandle doesn't change while we are using it on another thread 
     // t.join(); 
    } 
} 
+0

malloc вызывает только утечку памяти объемом 48 байтов. Сама программа использует 1200kb при запуске, когда я запускаю 10000 потоков на нем, использование памяти идет прямо до 5300kb, что логично, если вы считаете количество созданных потоков. Но не следует ли освобождать память, так как потоки останавливаются с _endthread? – Asmo

+0

Также я не могу использовать ваш подход, так как я не могу дождаться окончания потока. Мне нужно создать новый параллельный поток для каждого нового сокета. – Asmo

+0

Сделал это по-другому, altho использовал ваш ответ в качестве руководства! – Asmo

1

Каждый сокет использует некоторую память в операционной системе.

Вот описание в Linux: accept

ENOBUFS, ENOMEM 
      Not enough free memory. This often means that the memory 
      allocation is limited by the socket buffer limits, not by the 
      system memory. 

ОС не может очистить их.

Вы также пытаетесь создать 10000 потоков, это может также занять некоторую память, если создание не сработает задолго до того, как errno настроится на EAGAIN.