2016-08-09 9 views
0

pthreadsを使用するlinux用のソケットサーバーコードは次のとおりです。 私はこれをストレステストを開始した場合:ソケットサーバーメモリ使用量が増加し、応答しなくなる

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

メモリ増加についての270メガバイトに、サーバが応答しなくなった:のARMv7アーキテクチャに

271688 ./test 

これは短い時間がかかります。 forループを使ってリクエストを停止すると、メモリが解放されず、このサーバーが生産中に遅かれ早かれクラッシュする可能性があります。

でコンパイル:

$ gcc -lpthread -o test test.c 

次のコードで問題となる可能性がどのような約270メガバイトに

#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

物事は良くなりません。私は、これは、一般的にのARMv7上で動作しないと思います。あなたはARMv7 ** A **を意味しますか?またはARMv7 ** R **?おそらくARMv7 ** M **!そして、なぜこれはアーキテクチャの問題なのですか?アプリケーションレベルのコードではほとんどありません。 Re。コード:[ask]を参照し、[mcve]を提供してください。これはデバッグサービスではありません。 – Olaf

+2

'new_sock =のmalloc(1);'は 'new_sock = malloc関数を意味するものではありません(はsizeof(int型));' – cleblanc

+2

はMatch'は**非常に**悪いことである ''でinstr'ため 'const'修飾子を削除します!そして、他の野生のキャストも疑わしい。なぜあなたはコンパイラに助けにならないのですか?警告はあなたを助けるためのものであり、別の問題のあるキャストを追加するものではありません。 – Olaf

答えて

4

メモリが増加し、サーバーが応答しなく

なり作成したスレッドを切り離したり、結合したりする必要があります。それがまだ割り当てられているすべてのリソース(スタックと簿記データ)の周りzombiingされ終了し、各スレッドが立ったよう

。これにより、サーバーのメモリが消費されます。スレッドのデタッチを持つように

は、それが終了する前に、それは

pthread_detach(pthread_self()); 

を呼び出しています。スレッドに参加するには

pthread_create()によって返されたスレッドIDを渡し、他のスレッドのコールpthread_join()を持っています。プログラムとして

は、彼らが有利な解決策になるかもしれませんデタッチ、スレッドの結果に興味があるように思えません。コードはrecv()の結果をどのように処理するか


  • は、リソースリークとは関係のないコードを使用して他の問題があります。

  • ほとんどの関連する関数呼び出しのエラーチェックがありません。
  • new_sock = malloc(1);intあるnew_sockなどのために、いくつかのメモリに割り当てます。
  • cは、socklen_tである必要があります。そのアドレスに鋳造ハンマーを使用すると、
+0

一般的なルールとして、私は親スレッドがスレッドを切り離すのではなく、実際にスレッドを切り離すときに子スレッドを切り離すことをお勧めします。そうすれば、親はそれらを切り離して結合するかどうかを選択し、問題のスレッドはそれを知ったり気にする必要はありません。 –

関連する問題