2017-10-01 5 views
1

J'ai écrit un petit écouteur de test tcp. Ledit auditeur écoute le port 28328 et fonctionne de manière fantastique, attendez-vous à l'énorme fuite de ressources/mémoire qui se produit chaque fois qu'un client se connecte à lui.C++ Winsock Accepter Fuite de mémoire/Fuite de ressources

#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; 
} 

Alors que l'auditeur d'origine est beaucoup plus grand que cela et a probablement beaucoup plus de problèmes que je ne l'ai pas encore appris à, au moment ce mon plus gros problème.

Je suppose que le problème se produit à la suite de l'acceptation de la socket et il ne ferme pas correctement qui fuit alors à une fuite de poignée. Je me base sur le fait que lorsque j'ai regardé le gestionnaire de tâches et d'autres outils qui surveillent un processus, je peux voir le nombre de handles augmenter au même rythme que ma connexion.

Note:

1) Par le regard de celui-ci la fuite se produit sur la mémoire non paginée.

2) Ce même fragment de code, s'il est compilé et utilisé dans un environnement Linux, ne produira pas la même fuite de mémoire/ressource.

3) J'ai compilé et testé ce code sur plusieurs machines Windows et le même problème se produit.

4) (EDIT) J'ai vu quelques personnes avec ce problème sur des forums MSDN et des forums VS mais tout ce qu'on leur a dit de faire était de soumettre un ticket.

+1

"Ce même extrait de code si compilé et utilisé dans un environnement Linux" Votre code est spécifique à WinAPI et ne sera pas compilé ou exécuté de manière native dans un environnement Linux. – tambre

+0

@tambre Je sais, comme je l'ai dit sur le post c'est un écouteur de test à poster ici, ce n'est pas le code original et le code original peut être compilé sur windows et linux. N'oubliez pas, même si ce n'est pas le code original, le problème est toujours présent. Désolé de ne pas être plus précis. –

+0

@Asesh Oui, j'ai manqué cela ici mais je peux vous assurer que le code original le contient sur onexit –

Répondre

0

Il n'y a aucune fuite de mémoire dans l'application que vous avez montrée.

En raison du fonctionnement du protocole TCP/IP, les ressources associées aux connexions fermées ne peuvent pas être libérées immédiatement. Les paquets peuvent arriver hors service ou être retransmis après la fermeture de la connexion. Ainsi, même après un appel à closesocket, le socket du système d'exploitation actuel reste ouvert pendant une durée prédéfinie (habituellement 2-3 minutes, peut être ajusté avec TcpTimedWaitDelay).

Si vous exécutez netstat -an, vous verrez un tas de connexions dans CLOSE_WAIT ou état 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 
    . . . 

Bien sûr (noyau) est une mémoire nécessaire pour stocker ces états temporaires.

En outre, le numéro de port TCP de la plage éphémère ne peut pas être réutilisé immédiatement, ce qui signifie que le taux à laquelle vous pouvez ouvrir/fermer des connexions est assez limité.

+0

Je vois maintenant, d'une certaine manière il n'y a pas de solution à mon problème puisque mon application est supposée à des centaines de connexions dans un court laps de temps qui m'a causé plusieurs écrans bleus car la mémoire n'a pas été renvoyée assez rapidement. Eh bien au moins rien que je puisse faire de ce que je vois par votre suggestion de modifier TcpTimedWaitDelay. –

+0

Aussi, je vois ce que vous entendez par gamme éphémère, je vais y regarder un peu plus (faire un peu de googling) peut-être qu'il pourrait y avoir quelque chose hors de cette rage que mon aide ma situation un peu plus. Je vais donc essayer et changer la valeur que vous mentionnez, je vais rapporter avec mes conclusions. –

+0

@NotMyrealname Vous devriez également vous pencher sur le regroupement de connexions. – EJP

0

Le pool non paginé est une ressource du noyau et se rapporte à la mémoire qui ne peut pas être paginée par le système d'exploitation et est une ressource rare. Donc, garder un œil dessus, c'est une bonne chose. Le fait que ce soit dans le noyau, signifie que la mémoire n'est pas directement sous votre contrôle. Il se peut que la mémoire se rapporte à des paquets non envoyés, non traités, auquel cas la ressource est indirectement la responsabilité de votre programme.

Vérifiez la fuite de la poignée - d'où cela provient. Application Verifier Microsoft : Application Verifier download peut aider à identifier les piles d'appels qui présentent des fuites de mémoire et de poignées.