네트워크상에서 패킷 전송을 하는 프로그램입니다.
글쓴이: mydream / 작성시간: 월, 2015/11/30 - 4:14오후
네트워크상에서 특정 아이피의 일정 범위 포트로 패킷을 전송하는 프로그램입니다. 그런데 이 프로그램을 실행하면 메모리 점유률이 지속적으로 올라가기만 하고 프로그램을 종료해도 메모리 반환이 안됩니다. 즉 메모리가 누스되버리고 맙니다. 코드는 다음과 같습니다.
//#include <iostream> //using namespace std; #include "getopt.h" #include <cstdlib> //#pragma comment(lib, "Ws2_32.lib") //#include <winsock2.h> #include <windows.h> #pragma comment(lib, "Ws2_32.lib") //#include <Winsock2.h> #pragma comment(lib, "Shlwapi.lib") #include <Shlwapi.h> //Shlwapi.lib #pragma comment(lib, "Ole32.lib") #include <Objbase.h> //Ole32.lib #pragma comment(lib, "User32.lib") #include <Winuser.h> //User32.lib #include <cstdio> TCHAR* ip, *start_port, *end_port; unsigned int firstip_n, secondip_n, thirdip_n, fourthip_n; HWND hWnd; LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); void CALLBACK TimerProc(HWND, UINT, UINT, DWORD); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { //LPCTSTR clsname=TEXT("I am a window."); LPWSTR recmdline=GetCommandLine(); //LPCTSTR clsname=(LPCTSTR)strchr((char*)lpCmdLine, ' '); LPWSTR clsname=recmdline; /*ip=(LPWSTR)( StrChr(recmdline, TEXT(' ')) ); //LPWSTR iip=CharNextW(ip);// ip=ip+2; start_port=(LPWSTR)( StrChr(ip, TEXT(' ')) ); *start_port=0; start_port=start_port+1; end_port=(LPWSTR)( StrChr(start_port, TEXT(' ')) ); *end_port=0; end_port=end_port+1;*/ TCHAR* option=NULL; TCHAR* optarg; while( (option=getopt(recmdline, TEXT("-ip -sport -eport"), &optarg))!=NULL ) { if( StrCmp(option, TEXT("-ip"))==0 ) { ip=optarg; } else if( StrCmp(option, TEXT("-sport"))==0 ) { start_port=optarg; } else if( StrCmp(option, TEXT("-eport"))==0 ) { end_port=optarg; } } LPWSTR firstip=ip; LPWSTR secondip=(LPWSTR)StrChr(ip, TEXT('.')); *secondip=0; secondip=secondip+1; LPWSTR thirdip=(LPWSTR)StrChr(secondip, TEXT('.')); *thirdip=0; thirdip=thirdip+1; LPWSTR fourthip=(LPWSTR)StrChr(thirdip, TEXT('.')); *fourthip=0; fourthip=fourthip+1; firstip_n=(unsigned int)StrToInt(firstip); secondip_n=(unsigned int)StrToInt(secondip); thirdip_n=(unsigned int)StrToInt(thirdip); fourthip_n=(unsigned int)StrToInt(fourthip); WNDCLASS WndClass; WndClass.lpfnWndProc=WindowProc; WndClass.cbClsExtra=0; WndClass.cbWndExtra=0; WndClass.hCursor=LoadCursor(NULL, IDC_ARROW);// WndClass.hIcon=NULL; WndClass.hInstance=hInstance; WndClass.lpszClassName=clsname; WndClass.lpszMenuName=NULL; WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);// WndClass.style=CS_HREDRAW|CS_VREDRAW;// RegisterClass(&WndClass); /* HWND WINAPI CreateWindow( _In_opt_ LPCTSTR lpClassName, _In_opt_ LPCTSTR lpWindowName, _In_ DWORD dwStyle, _In_ int x, _In_ int y, _In_ int nWidth, _In_ int nHeight, _In_opt_ HWND hWndParent, _In_opt_ HMENU hMenu, _In_opt_ HINSTANCE hInstance, _In_opt_ LPVOID lpParam ); */ hWnd=CreateWindow(clsname, thirdip, WS_OVERLAPPEDWINDOW,0,0,0,0, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, SW_HIDE); MSG Message; while(GetMessage(&Message, NULL, 0,0)) { TranslateMessage(&Message); DispatchMessage(&Message); } return (int)Message.wParam; } DWORD WINAPI ThreadFunc(LPVOID temp) { //argv[1] ip address //argv[2] start port number //argv[3] end port number SOCKET ConnectSocket; sockaddr_in clientService; clientService.sin_family=AF_INET; char arrip[20]; sprintf_s(arrip,"%d.%d.%d.%d",firstip_n, secondip_n, thirdip_n, fourthip_n); //clientService.sin_addr.s_addr=inet_addr(arrip);/////////////////solving clientService.sin_addr.S_un.S_addr=inet_addr(arrip); unsigned int port; unsigned int start_port_n=(unsigned int)StrToInt(start_port); port=start_port_n; unsigned int end_port_n=(unsigned int)StrToInt(end_port); const char* sendbuf="Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day! Beautiful day!"; while(true) { WSADATA wsaData; int iResult=WSAStartup(MAKEWORD(2,2),& wsaData); if(iResult!=NO_ERROR) { //cout<<"Error occured."<<endl; MessageBox(hWnd, TEXT("WSAStartup function failed."), NULL, MB_OK); WSACleanup(); return 1; } ConnectSocket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(ConnectSocket==INVALID_SOCKET) { MessageBox(hWnd, TEXT("socket function failed."), NULL, MB_OK); WSACleanup(); return 1; } clientService.sin_port=htons(port); /*iResult=connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService)); if(iResult==SOCKET_ERROR) { //cout<<"Fail to connect."<<endl; WSACleanup(); return 1; }*/ iResult=sendto(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0,(SOCKADDR*)&clientService, sizeof(clientService)); if(iResult==SOCKET_ERROR) { closesocket(ConnectSocket); WSACleanup(); return 1; } port++; //cout<<port<<" ";//test if(port>=end_port_n) { port=start_port_n; } closesocket(ConnectSocket); //Sleep(5); WSACleanup(); } return 0; } LRESULT CALLBACK WindowProc(HWND hwnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { DWORD ThreadId; HANDLE hThread; switch(iMessage) { case WM_CREATE: hThread=CreateThread(NULL, 0, ThreadFunc, NULL, 0, &ThreadId); //SetTimer(hwnd, 1, 1, TimerProc); return true; case WM_DESTROY: //KillTimer(hwnd, 1); CloseHandle(hThread); PostQuitMessage(0); return 0; } return ( DefWindowProc(hwnd, iMessage, wParam, lParam) ); }
ThreadFunc 함수에서 패킷을 보내도록 while 루프를 도는 중에 메모리 누수 문제가 발생하는군요. 어떻게 이 문제를 해결해야 하나요? 해당 프로그램 사용법은 cmd에서
파일이름 -ip 155.156.157.123 -sport 5000 -eport 20000
이렇게 합니다. 그러면 155.156.157.123 주소의 5000 포트부터 20000 포트까지 패킷을 보냅니다. 메모리 누수가 어디서 발생하는 것이며 어떻게 해결해야 하는지좀 알려주시면 감사하겠습니다.
Forums:
몇가지 참고하시기 바랍니다.
- 각 함수에 인자값. 리턴값. 오류값을 MSDN 에서 확인합니다.
- GetCommandLine() 에 대한 처리 방법이 적용되지 않을 경우에 대한 예외 처리를 하셔야 합니다.
- 이와 같이 사용하면. 윈도우에서도 printf() 를 사용하실 수 있습니다.
AllocConsole();
freopen( "CONOUT$", "wt", stdout );
- setlocale() 로 지역설정을 지정하실 수 있습니다.
- 문자열에 따라서. 사용하는 함수와 방식이 다르니 주의하셔야 합니다.
Ansi Unicode TCHAR
strlen() wcslen() _tcslen()
- 오류값은 DWORD GetLastError() 가 있고. int WSAGetLastErro() 가 있습니다.
- 소켓 초기화는 한번만 해주시면 됩니다.
- 스레드 변수를 전역으로 사용하셔야 하며. 종료시에 잘못된 스레드 변수값인지. 확인하는 조건문이 필요합니다.
- CPU 와 메모리 점유율을 확인하시기 바랍니다.
- GDI. Thread. Handle 갯수를 윈도우 작업관리자에서 확인하실 수 있습니다. (옵션에서 추가해야 합니다.)
테스트 한 소스파일을 파일로 첨부합니다.
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
#if 0은 뭘 하는 것인가요?
#if 0
//statement
#endif
#if 0은 무엇이고 그 사이에 있는 것은 어떻게 되는 것인가요? 0은 거짓이기 때문에 저 statement는 컴파일시 포함되지도 않을 것이고 실행도 안될텐데요. 일종의 주석과 같은 역할로 추가하신 것인가요?
/* */ 귀찮아서. 대신 사용합니다.
...
사용 안함
#if 0
#endif
사용 함
#if 1
#endif
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
답변 감사합니다. 해결했습니다.
소켓관련 구조체를 0으로 초기화하지 않아서 생기는 문제였나봅니다. memset로 소켓 구조체를 0으로 초기화하니 누수 발생이 멈추는군요. 여러모로 감사드리고요, 콘솔에서 점검하는 방법도 있다는 것을 알려주셔서 감사합니다.
그런데 에러 점검 WSAGetLastError에 대해 다음과 같은 글이 언급돼 있는데요..
msdn에서 퍼왔습니다.
출처: https://msdn.microsoft.com/en-us/library/windows/desktop/ms742213(v=vs.85).aspx
If successful, the WSAStartup function returns zero. Otherwise, it returns one of the error codes listed below.
The WSAStartup function directly returns the extended error code in the return value for this function. A call to the WSAGetLastError function is not needed and should not be used.
WSAStartup 함수가 성공적이면, 이 함수는 0을 반환하고, 그렇지 않으면 아래 언급된 오류 코드중 하나를 반환한다. WSAStartup 함수는 반환값에서 연장된 오류 코드를 직접 반환한다. WSAGetLastError 함수는 필요치 않으며 사용되지 않는 편이 좋다.
WSAStartup이 반환한 값을 직접 오류 상수와 비교해도 될까요?
참고하세요.
컴파일이 안되니 눈으로 확인할 수 밖에 없는데요.
아무리 봐도 메모리 누수가 발생할만한 코드는 없어 보입니다. ㅡㅅㅡ)???
어디선가 메모리 할당하는 코드가 보여야 되는데요.. 할당하는 코드가 없으니, 누수가 발생할리도 없을 듯 싶은데요..;;
메모리 누수는 어떤 방식으로 확인을 하셨는지요?
https://msdn.microsoft.com/ko-kr/library/windows/desktop/e5ewb1h3(v=vs.80).aspx
ㄴ이걸 참고해서 정말로 메모리 누수가 발생하는지, 발생한다면 어디서 발생하는지 알아보시기 바랍니다.
출력창의 메모리 누수 내용을 더블클릭하면 추정되는 해당 코드 위치를 알려줍니다.
약간 미심적은 코드는...
이 부분이 될듯 싶은데요.
ip, start_port, end_port등이 배열이 아닌 포인터로 선언이 되어있는데..
이러한 방식으로 문자열을 직접 조작을 한다는 것은 getopt()라는 라이브러리 내부에서 메모리 할당을 받는 것이 아닌지 추측됩니다.
실행인수를 할당받은후에 free를 해줘야 하는 것이 아닌지 라이브러리 사용 설명서를 다시 확인해 보십시요.
그리고, 질문에는 없지만 윈도우 소켓에이전트(WSAxxxx)의 초기화는 처음 한번만 해주시면 됩니다.
매번 Startup, clean 해주실 필요는 없으니 루프 밖으로 빼십시오.
마지막으로 테스트 코드인듯 싶으니 별 상관 없겠지만 위 코드대로라면 프로그램은 영영 종료되지 않고, 강제 종료를 시키기 전까지는 종료 시키지도 못합니다. 이에 대한 것도 추가해 두시면 좋을듯 싶습니다.
getopt() 함수를 참고하시기 바랍니다.
숫자 getopt (숫자. 문자열. 상수 문자열)
int getopt (int argc, char *const *argv, const char *shortopts)
http://forum.falinux.com/zbxe/?mid=C_LIB&page=3&document_srl=408382
다른 함수를 사용하셨거나. 잘못 사용하셨습니다.
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
아... 그렇군요.
댓글 감사드립니다.
참고 많이 하고 있습니다.
댓글 달기