2016-08-09 118 views
0

Ich habe den folgenden Socket-Server-Code für Linux mit Pthreads. Wenn ich Stresstests dies mit Start:Socket Server Speicherverbrauch steigt, reagiert nicht mehr

for ((;;)); do echo STAT | nc 127.0.0.1 5555 ; done 

der Speicher steigt auf etwa 270MB dann der Server reagiert nicht mehr:

271688 ./test 

Auf ARMv7-Architektur dies dauert eine kürzere Zeit. Wenn ich die Anfragen mit der for-Schleife beende, wird der Speicher nicht frei, was bedeutet, dass dieser Server früher oder später in der Produktion abstürzen würde.

Kompiliert mit:

$ gcc -lpthread -o test test.c 

Was ist das Problem im folgenden Code sein kann:

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <stdint.h> 
#include <fcntl.h> 
#include <termios.h> 
#include <errno.h> 
#include <sys/ioctl.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <pthread.h> 

char *Match(const char *instr, const char *pattern) { 
    const char *p, *q; 
    for (; *instr; instr++) { 
     for (p = instr, q = pattern; *p && *q; p++, q++) 
      if (*p != *q) break; 
     if (p == q || *q == 0) return (char *)instr; 
    } 
    return NULL; 
} 

void *connection_handler2(void *socket_desc) { 
    int sock = *(int*)socket_desc; 
    int comm, i; 
    int read_size; 
    char *message, client_message[500], data[50]; 
    char buf[256]; 

    strcpy(data, "Test message back"); 

    message = "Hello this is test Server\n"; 
    write(sock, message, strlen(message)); 

    while ((read_size = recv(sock, client_message, 500, 0)) > 0) { 
     if (Match(client_message, "STAT") != NULL) { 
      write(sock, data, strlen(data)); 
     } 
     if (Match(client_message, "QUIT") != NULL) break; 
    } 

    if (read_size == 0) { 
     puts("Client disconnected"); 
     fflush(stdout); 
    } else 
    if (read_size == -1) { 
     perror("recv failed"); 
    } 

    close(sock); 
    //Free the socket pointer 
    free(socket_desc); 

    return 0; 
} 

void *s2_thread() { 
    int n, i; 
    int opt = 1; 
    int socket_desc, client_sock, c, *new_sock; 
    struct sockaddr_in server, client; 
    struct termios toptions; 

    //Create socket 
    socket_desc = socket(AF_INET, SOCK_STREAM, 0); 
    if (socket_desc == -1) { 
     printf(" Could not create socket"); 
    } 

    //Prepare the sockaddr_in structure 
    server.sin_family = AF_INET; 
    server.sin_addr.s_addr = INADDR_ANY; 
    server.sin_port = htons(5555); 
    //bind the socket to the address 
    setsockopt(socket_desc, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(int)); 

    //Bind 
    if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) { 
     //print the error message 
     perror("port 5000 bind failed"); 
     return; 
    }  
    //Listen 
    listen(socket_desc, 3); 

    //Accept 
    c = sizeof(struct sockaddr_in); 

    //Endless main loop 
    while ((client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c))) { 
     pthread_t t2; 
     new_sock = malloc(1); 
     *new_sock = client_sock; 

     if (pthread_create(&t2, NULL, connection_handler2, (void*)new_sock) < 0) { 
      return; 
     } 
    } 

    if (client_sock < 0) { 
     return; 
    } 
    return; 
} 

int main(int argc, char *argv[]) { 
    int n, i; 
    int opt = 1; 
    int socket_desc, client_sock, c, *new_sock; 
    struct sockaddr_in server, client; 

    pthread_t ss2t; 

    if (pthread_create(&ss2t, NULL, s2_thread, NULL) < 0) { 
     return 1; 
    } 

    puts("Telnet server started"); 

    while (1) sleep(5); 

    return 0; 
} 
+0

Ich glaube nicht, dass dies auf ARMv7 im Allgemeinen funktioniert. Du meinst ARMv7 ** A **? Oder ARMv7 ** R **? Sehr wahrscheinlich nicht ARMv7 ** M **! Und warum denkst du, das ist ein Problem der Architektur? Sehr unwahrscheinlich für Code auf Anwendungsebene. Re. der Code: Siehe [fragen], stellen Sie ein [mcve] zur Verfügung. Dies ist kein Debugging-Service. – Olaf

+2

'new_sock = malloc (1);' meinst du nicht 'new_sock = malloc (sizeof (int));' – cleblanc

+2

Entfernen von 'const' Qualifier für' instr' in 'Match' ist eine ** sehr ** schlechte Sache ! Und die anderen wilden Würfe sind auch suspekt. Warum lässt dich der Compiler nicht helfen?Warnungen sollen Ihnen helfen, keine weitere problematische Besetzung hinzuzufügen. – Olaf

Antwort

4

Die Speicher steigt auf etwa 270MB dann der Server nicht mehr reagiert

Sie möchten entweder die erstellten Threads lösen oder ihnen beitreten.

So wie es steht, zoomt jeder Thread, der endete, mit all seiner Ressource (Stapel- und Buchhaltungsdaten), die noch zugeteilt wird. Dies verschlingt den Speicher des Servers.

ein Gewinde detach haben, müssen es

pthread_detach(pthread_self()); 

aufrufen, bevor er endet.

Um einem Thread beizutreten, haben Sie einen anderen Thread-Aufruf pthread_join() übergeben die Thread-ID wie von pthread_create() zurückgegeben.

Da das Programm nicht an den Ergebnissen der Threads interessiert zu sein scheint, ist es wahrscheinlich die beste Lösung, sie zu entfernen.


Es gibt andere Probleme mit dem Code, der auf die Ressource Leck nicht verwandt sind:

  • , wie der Code das Ergebnis recv() abwickelt.
  • Fehlerprüfung für die meisten relevanten Funktionsaufrufe fehlt.
  • new_sock = malloc(1); reserviert zu wenig Speicher für eine int als new_sock ist.
  • c sollte vom Typ socklen_t sein. Mit dem Casting Hammer auf seine Adresse macht es nicht besser
+0

Als allgemeine Regel würde ich vorschlagen, dass die übergeordneten Threads ihre untergeordneten Threads trennen, wenn sie tatsächlich getrennt werden sollen, anstatt dass sich Threads ablösen. Auf diese Weise kann der Elternteil entscheiden, ob er sie entfernen und sich ihnen anschließen möchte, und der betreffende Thread muss nicht wissen oder sich darum kümmern. –