2017-10-01 5 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 포럼에 게시 한이 정확한 문제로 몇 사람을 보았지만 티켓을 제출하라는 메시지가 모두 들었습니다.

+1

"이 코드는 Linux 환경에서 컴파일되고 사용되는 경우 동일한 코드 조각입니다."이 코드는 WinAPI에 고유하며 Linux 환경에서 기본적으로 컴파일되거나 실행되지 않습니다. – tambre

+0

@tambre 여기에 게시 할 테스트 리스너라고 말한 것처럼 원래 코드는 아니며 Windows 및 Linux에서 원본 코드를 컴파일 할 수 있습니다. 원본 코드가 아니더라도 문제가 계속되는 것을 명심하십시오. 더 구체적이지 않아서 미안해. –

+0

@Asesh 예, 여기서 그립습니다.하지만 원래 코드에는 onexit이 포함되어 있음을 확신 할 수 있습니다. –

답변

0

표시 한 응용 프로그램에는 메모리 누수가 없습니다.

TCP/IP가 작동하는 방식 때문에 닫힌 연결과 관련된 리소스를 즉시 해제 할 수 없습니다. 연결이 닫힌 후에 패킷이 도착하지 못하거나 재전송 될 수 있습니다. 따라서 closesocket으로 전화를 한 후에도 실제 OS 소켓은 미리 정의 된 시간 (일반적으로 2-3 분, TcpTimedWaitDelay로 조정 가능) 동안 열려 있습니다. 물론 (커널) 메모리는 이러한 임시 상태를 저장하기 위해

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 
    . . . 

을 필요 :

당신이 netstat -an을 실행하면

, 당신은 CLOSE_WAIT 또는 TIME_WAIT 상태에있는 연결의 무리를 볼 수 있습니다.

또한 임시 포트 범위의 TCP 포트 번호를 즉시 다시 사용할 수 없기 때문에 연결을 열거 나 닫을 수있는 속도 인 이 매우 제한적입니다.

+0

지금까지 볼 수 있듯이 내 응용 프로그램은 짧은 시간 내에 수백 개의 연결로되어있어 메모리가 충분히 빨리 반환되지 않아 여러 개의 파란색 화면이 표시되기 때문에 문제가 해결되지 않았습니다. 적어도 TcpTimedWaitDelay 수정에 대한 제안으로 볼 수있는 것은 아무것도 없습니다. –

+0

또한 임시 범위로 무엇을 의미하는지, 조금 더 살펴볼 것입니다 (검색 중 일부) 어쩌면 내 상황이 좀 더 도움이 될만한 분노가있을 수도 있습니다. 나는 당신이 언급 한 가치를 바꾸려고 노력할 것이고, 나는 나의 발견과 함께보고 할 것이다. –

+0

@NotMyrealname 연결 풀링도 고려해야합니다. – EJP

0

비 페이징 풀은 커널 리소스이며 운영 체제에서 페이징 할 수없는 메모리와 관련이 있으며 부족한 리소스입니다. 그래서 그것에주의를 기울이는 것은 좋은 일입니다.

사실 커널에 있다는 것은 메모리가 사용자 컨트롤에 직접 있지 않다는 것을 의미합니다. 메모리가 보내지 지 않은, 처리되지 않은 패킷과 관련이있을 수 있습니다.이 경우 리소스는 프로그램의 간접적 인 책임입니다.

어디에서오고 있는지 핸들 누출을 점검하십시오. 응용 프로그램 검증 자 Microsoft : Application Verifier download은 메모리 및 핸들 누수가있는 호출 스택을 식별하는 데 도움을 줄 수 있습니다.