2012-04-29 14 views
0

私はTCPを使ってネットで動作するツールの開発を開始します。これはウェブサーバの簡単な機能を提供します。メモリ/スレッドリークWinSock2で簡単なHTTPサーバを開発する

私は非常に悪いミスを持っている私のプログラムをテストするには

  • メモリは、あなたがの1,5〜についてが表示されることがあり
  • Taskmgr.exeので
  • すぐスレッドの数千を作成

をリークスレッドと約50kbの割り当てられたメモリがあります。 また、プログラムを32ビットとしてコンパイルしましたが、vmmapユーティリティでは64ビットのスタックが多数表示されることがあります。私のOSは64ビットですが、taskmgr.exeでは* 32が表示されますが、32ビットプログラムが64ビットスタックをどのように使用しているかはわかりませんが、64ビットOSで32ビットプログラムを起動するのは普通ですが、あなたが私にこの質問についてのアドバイスをくれれば、私は非常に満足しています。

なぜ、私のプログラムはすぐに多くのスレッドを作成しましたか? (間違いなく、while(真)ブロックの原因)

しかし、私は次をしたい:

  • リクエストが処理された場合には、それぞれの新しい要求
  • ため、各スレッドを作成し、その後、スレッドと自由にメモリを終了

どのようにすべきです私のコードをリメイクしますか?

ありがとうございました!ここで

は私のコード(MS VC++ 9)である:

#include <iostream> 
#include <Windows.h> 

#pragma comment(lib, "Ws2_32.lib") 

typedef struct Header 
{ 
friend struct Net; 

private: 
    WORD wsa_version; 
    WSAData wsa_data; 

    SOCKET sock; 
    SOCKADDR_IN service; 

    char *ip; 
    unsigned short port; 

public: 
    Header(void) 
    { 
     wsa_version = 0x202; 

     ip = "0x7f.0.0.1"; 
     port = 0x51; 

     service.sin_family = AF_INET; 
     service.sin_addr.s_addr = inet_addr(ip); 
     service.sin_port = htons(port); 
    } 

} Header; 

typedef struct Net 
{ 
private: 
    int result; 

    HANDLE thrd; 
    DWORD exit_code; 

    void WSAInit(WSAData *data, WORD *wsa_version) 
    { 
     result = WSAStartup(*wsa_version, &(*data)); 

     if(result != NO_ERROR) 
     { 
      std::cout << "WSAStartup() failed with the error: " << result << std::endl; 
     } 
     else 
     { 
      std::cout << (*data).szDescription << " " << (*data).szSystemStatus << std::endl; 
     } 
    } 

    void SocketInit(SOCKET *my_socket) 
    { 
     (*my_socket) = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

     if((*my_socket) == INVALID_SOCKET) 
     { 
      std::cout << "Socket initialization failed with the error: " << WSAGetLastError() << std::endl; 
      WSACleanup(); 
     } 
     else 
     { 
      std::cout << "Socket initialization successful!" << std::endl; 
     } 
    } 

    void SocketBind(SOCKET *my_socket, SOCKADDR_IN *service) 
    { 
     result = bind((*my_socket), (SOCKADDR*)&(*service), sizeof(*service)); 

     if(result == SOCKET_ERROR) 
     { 
      std::cout << "Socket binding failed with the error: " << WSAGetLastError() << std::endl; 
      closesocket((*my_socket)); 
      WSACleanup(); 
     } 
     else 
     { 
      std::cout << "Socket binding successful!" << std::endl; 
     } 

     result = listen(*my_socket, SOMAXCONN); 

     if(result == SOCKET_ERROR) 
     { 
      std::cout << "Socket listening failed with the error: " << WSAGetLastError() << std::endl; 
     } 
     else 
     { 
      std::cout << "Listening to the socket..." << std::endl; 
     } 
    } 

    static void SocketAccept(SOCKET *my_socket) 
    { 
     SOCKET sock_accept = accept((*my_socket), 0, 0); 

     if(sock_accept == INVALID_SOCKET) 
     { 
      std::cout << "Accept failed with the error: " << WSAGetLastError() << std::endl; 
      closesocket(*my_socket); 
      WSACleanup(); 
     } 
     else 
     { 
      std::cout << "Client socket connected!" << std::endl; 
     } 

     char data[0x400]; 
     int result = recv(sock_accept, data, sizeof(data), 0); 
     HandleRequest(data, result); 
     char *response = "HTTP/1.1 200 OK\r\nServer: Amegas.sys-IS/1.0\r\nContent-type: text/html\r\nSet-Cookie: ASD643DUQE7423HFDG; path=/\r\nCache-control: private\r\n\r\n<h1>Hello World!</h1>\r\n\r\n"; 
     result = send(sock_accept, response, (int)strlen(response), 0); 

     if(result == SOCKET_ERROR) 
     { 
      std::cout << "Sending data via socket failed with the error: " << WSAGetLastError() << std::endl; 
      closesocket(sock_accept); 
      WSACleanup(); 
     } 
     else 
     { 
      result = shutdown(sock_accept, 2); 
     } 
    } 

    static void HandleRequest(char response[], int length) 
    { 
     std::cout << std::endl; 

     for(int i = 0; i < length; i++) 
     { 
      std::cout << response[i]; 
     } 

     std::cout << std::endl; 
    } 

    static DWORD WINAPI Threading(LPVOID lpParam) 
    { 
     SOCKET *my_socket = (SOCKET*)lpParam; 
     SocketAccept(my_socket); 

     return 0; 
    } 

public: 
    Net(void) 
    { 
     Header *obj_h = new Header(); 

     WSAInit(&obj_h->wsa_data, &obj_h->wsa_version); 

     SocketInit(&obj_h->sock); 
     SocketBind(&obj_h->sock, &obj_h->service); 

     while(true) 
     { 
      thrd = CreateThread(NULL, 0, &Net::Threading, &obj_h->sock, 0, NULL); 

      //if(GetExitCodeThread(thrd, &exit_code) != 0) 
      //{ 
      // ExitThread(exit_code); 
      //} 
     } 

     delete &obj_h; 
    } 
} Net; 

int main(void) 
{ 
    Net *obj_net = new Net(); 

    delete &obj_net; 

    return 0; 
} 
+1

あなたは '* pointer-to-pointer *を削除してはいけません。' delete&obj_net'ではなく 'delete obj_net'を使用してください。 (あるいはboost :: scoped_ptrのようなスマートなポインタを使うのが良い) – Abyx

+2

@Abyx:std :: unique_ptrのような標準のスマートポインタを使うのが良いです。 –

+1

@RobertMason、VC++ 9には 'unique_ptr'はありません。 – Abyx

答えて

3

あなたはあなたが前に、接続を受け入れない AFTERスレッドを作成する必要があります。

あなたがやっていることは、大量のスレッドを作成し、それぞれが接続を待つことです。それらの多くは何もしていません。 Windowsの呼び出しがスレッドセーフであるかどうかはわかりません。同じ接続を処理する複数のスレッドが存在する可能性があります。

代わりに行う必要があるのは、メインループ(ネットのコンストラクタwhile(true))でaccept()を呼び出す必要があることです。接続があるまでaccept()ブロックをブロックするので、誰かが接続を試みるまでメインスレッドが待機します。次に、その接続を処理する別のスレッドを作成します(または、おそらくはUNIXで処理する可能性があります)。したがって、ループは次のようになります。

次に、SocketAcceptからこのループに移動したコードを削除します。そして、美容目的のために、SocketAcceptの名前をSocketHandleConnectionに変更します。

スレッドが開始されると、既に接続が確立されているため、データ(たとえば、charデータ[0x400]から開始する操作)を処理するだけで済みます。

接続のクリーンアップを処理する場合は、これを行う方法がいくつかあります。1つはスレッド化されているので、スレッドに独自のクリーンアップをさせることができます。メインプロセスとメモリを共有するので、これを行うことができます。しかし、この例では、私はあなたがきれいにする必要があるものは何も表示されません。

最後に、あなたはExitThreadが何をしているのか理解していないと思います。 MSDNによると:

ExitThreadは、Cコードでスレッドを終了するのに推奨される方法です。ただし、C++コードでは、 スレッドは、デストラクタを呼び出す前に終了するか、他の自動クリーンアップ を実行することができます。したがって、C++コードでは、スレッド関数から戻る必要があります。

したがって、ExitThreadを呼び出す必要はありません。関数から戻るだけで、スレッドは自動的に終了します。メインスレッドから呼び出す必要はありません。

最後に、C++ 11の新しい標準C++スレッドを実際に使用する必要があります。そして、boost :: asioにコードを移植するための少しの努力を払うと、 D

免責事項:ほとんどの私の経験はUNIXに関連しているため、私はWindowsを理解しています。私はできる限り正確にしようとしましたが、この知識がどのようにWindowsに変換するかについて私が誤解している場合は、私はあなたに警告しました。

+0

コード(正しい場所)を強調表示するのに手伝ってください。どうすれば変更できますか?どうもありがとうございました! – Secret

+0

停止!その前後の違いは何ですか?スレッドの作成/終了は、WinSockでの接続の処理とは独立しています。スレッドリークは接続を処理するためではありませんが、そうではありませんか? – Secret

+1

私の編集した答えを見てください。スレッドリークは、何もする必要のない膨大な数のスレッドを作成し、接続して永久に待つだけです。あなたのコードが非常に多くのスレッドを作成することによってクラッシュしていないのに驚いています。たぶんCreateThreadが失敗し、失敗をチェックしていない可能性がありますか? –

2

なぜスレッドを無限ループで作成していますか?これは、もちろん、たくさんのスレッドを作成します。私はこのコードを参照しています:

+0

新しい接続と方法私はそれらを処理する必要がありますか?私が理解しているように、新しい接続ごとに新しいスレッドを作成し、それを処理しなければならないので、どうすればそれを開発できますか?ありがとうございました! – Secret

+1

新しいソケットをAccept'edした後にスレッドを作成します。しかし、1つの特別なスレッドでのみAcceptを呼び出します。 – usr

+0

1つの特別なスレッド? 「1つの特別な」という意味は何ですか?愚かな質問を申し訳ありません。 – Secret

関連する問題