2017-10-01 83 views
1

私は小さなテスト用のtcpリスナーを作成しました。上記のリスナーはポート28328をリッスンし、クライアントが接続するたびに発生する巨大なリソース/メモリリークを予想して素晴らしい動作をします。C++ Winsock Acceptメモリリーク/リソースリーク

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

元リスナーはこれよりもはるかに大きいと、おそらく私は今、この私の最大の問題のように、まだにもらっていない多くの問題がありますが。

私は、ソケットの受け入れの結果として問題が発生し、それが正しく閉じずにハンドルリークに漏れたと考えます。私は、プロセスを監視するタスクマネージャーやその他のツールを見たとき、私の接続が発生したのと同じ割合でハンドル数が増えるのが分かります。

注:

1)その様子によってはリークが非ページメモリに発生します。

2)Linux環境でコンパイルされて使用された場合と同じコードスニペットでは、同じメモリ/リソースリークが発生しません。

3)このコードを複数のWindowsマシンでコンパイルしてテストしましたが、同じ問題が発生します。

4)(EDIT)MSDNフォーラムやVSフォーラムに掲載されたこの問題を抱えている人が2人いましたが、チケットを提出するだけでした。

+1

"コンパイルしてLinux環境で使用する場合、これと同じコードスニペット"あなたのコードはWinAPI固有であり、Linux環境でネイティブにコンパイルまたは実行されません。 – tambre

+0

@tambre私が知っているように、これはここに投稿するテストリスナーです。これはオリジナルのコードではなく、オリジナルのコードはWindowsとLinuxでコンパイルできます。 元のコードではないにもかかわらず、この問題は依然として存在します。より具体的ではないことを申し訳ありません。 –

+0

@Aseshはい、私はここでそれを逃したが、私は元のコードはonexitにそれが含まれていることを保証することができます –

答えて

0

表示されているアプリケーションにメモリリークはありません。

TCP/IPが機能するため、クローズされた接続に関連付けられたリソースはすぐに解放できません。パケットは、接続が閉じられた後に到着しないか、再送信される可能性があります。したがって、closesocketへの呼び出しの後でさえ、実際のOSソケットはあらかじめ定義された時間(通常2〜3分、TcpTimedWaitDelayで調整することができます)開いたままです。

あなたがnetstat -anを実行する場合は、CLOSE_WAITや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 
    . . . 

(カーネル)のメモリは、これらの一時的な状態を記憶するために必要とされます。

さらに、一時的な範囲のTCPポート番号をすぐに再使用することはできません。つまり、接続を開く/閉じることができるレートが非常に限られています。

+0

私の問題は解決方法がありません。短いアプリケーションで何百もの接続が想定されているため、メモリが十分に戻ってこないため、複数のブルースクリーンが表示されています。私がTcpTimedWaitDelayを修正する提案から見るものは、少なくとも何もできません。 –

+0

また、あなたは一時的な範囲の意味を参照してください、私はもう少し(いくつかのグーグルを行う)を見てみましょう多分私の状況をもう少し助けてその怒りの何かがあるかもしれない。私はあなたが言及した価値を変えようと努力します、私は私の発見と一緒に報告します。 –

+0

@NotMyrealnameあなたは接続プーリングについても調べる必要があります。 – EJP

0

非ページプールは、カーネルリソースであり、オペレーティングシステムによってページングできないメモリであり、希少なリソースです。だからそれを見守って、良いことです。

実際にカーネル内にあるということは、メモリが直接あなたのコントロールにないことを意味します。メモリーが未送信、未処理のパケットに関連している可能性があります。この場合、リソースはプログラムの間接的な責任になります。

ハンドルリークを確認してください。アプリケーションベリファイヤMicrosoft : Application Verifier downloadは、メモリとハンドルをリークしているコールスタックを識別するのに役立ちます。

関連する問題