Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > C/C++ Сетевое программирование
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 05.10.2012, 14:05   #1
_angry
Новичок
Джуниор
 
Регистрация: 05.10.2012
Сообщений: 2
По умолчанию IOCP и возможная утечка памяти

Делаю приложение на IOCP. Заметил, что после подключения и отключения клиентов количество дескрипторов (в диспетчере задач) не возвращается к первоначальному. Упростил всю логику до предела. Ниже полный код класса, при работе которого видна утечка хэндлов. Это демка, упрощенная до нельзя. Буду очень благодарен, если вы попробуете собрать проект у себя и выскажете свои мысли. Делаем пустой консольный проект с поддержкой mfc, в _tmain создаем экземпляр класса, вызываем метод Start. Нужна помощь. У кого какие мысли?
header
Код:
#include "Mutex.h"

typedef struct
{
	void * m_This;
	int    m_ThreadNumber;
}TIOCPParams;

typedef struct 
{
	OVERLAPPED m_ovrl;
	SOCKET     m_sock;  
}TMYOVERLAPPED;

class CD2Class  
{
public:
	int IOCPThread(TIOCPParams * pParams);
	int Stop();
	int Start();

	CD2Class();
	virtual ~CD2Class();

	HANDLE m_threadEvent;
	HANDLE m_hIocp;
	CMutex m_Mutex;
	int m_stop;
	int m_opcnt;
};
source
Код:
int gIOCPThread(void * pParams)
{
	TIOCPParams ThreadParams = *(TIOCPParams *)pParams;
	CD2Class * pD2 = (CD2Class *)ThreadParams.m_This;
	return pD2->IOCPThread( &ThreadParams );
}

CD2Class::CD2Class() : m_Mutex(0)
{
	m_stop = 0;
	m_hIocp = NULL;
	m_threadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	m_opcnt = 0;
}

CD2Class::~CD2Class()
{
	CloseHandle( m_threadEvent );
}

int CD2Class::Start()
{
	int i, nRet = 0, threads = 1, cnt = 0;	
	struct sockaddr_in addr;			
	WSAData	wsData;		
	SYSTEM_INFO si;
	struct sockaddr_in clientaddr;	
	int length = sizeof(clientaddr);	
	ULONG lngMode = 1;
	TMYOVERLAPPED * pOvrl = NULL;
	SOCKET listensocket, clientsocket;
	int blnBindLocal = 1;
	WORD port = 5001;

	m_stop = 0;

	/////////////////////////////
	GetSystemInfo(&si);
	/////////////////////////////
	

	if( (nRet = WSAStartup( MAKEWORD(2, 2), &wsData )) < 0 ) {
		return false;
	}

	if ( (listensocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) {
		return false;
	}
	
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = (blnBindLocal) ? inet_addr("127.0.0.1") : htonl(INADDR_ANY);	
	
	if ( (nRet = bind( listensocket, (struct sockaddr *) &addr, sizeof(addr) )) < 0 ) {
		closesocket (listensocket );
		return false;
	}
	
	if ( (nRet = listen( listensocket, 100 )) < 0 ) {
		closesocket (listensocket );
		return false;
	}	
	
	if ( (m_hIocp = ::CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 )) == NULL ) {
		closesocket (listensocket );
		return false;
	}
	/////////////////////////////////////////////////////////////////////////////////////////

	threads = (si.dwNumberOfProcessors);

	for(i=0;i<(int)threads;i++) {

		TIOCPParams params;
		CWinThread * pThread = NULL;

		memset(&params, 0, sizeof(params));
		ResetEvent(m_threadEvent);		

		params.m_This = this;
		params.m_ThreadNumber = i;

		pThread = AfxBeginThread((AFX_THREADPROC)gIOCPThread, &params, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
			
		pThread->m_bAutoDelete = true;
		pThread->ResumeThread();
		
		Sleep(10);

		WaitForSingleObject(m_threadEvent, INFINITE);
	}	
	
	while( m_stop == 0 ) {

		pOvrl = new TMYOVERLAPPED();
		memset(pOvrl, 0, sizeof(*pOvrl));
		
		if ( (pOvrl->m_sock = accept(listensocket, (struct sockaddr *)&clientaddr, &length)) != INVALID_SOCKET ) {

			m_Mutex.Lock();
			m_opcnt++;
			m_Mutex.Unlock();
			
			printf("connection #%u\r\n", ++cnt);

			if (ioctlsocket(pOvrl->m_sock, FIONBIO, (u_long FAR*) &lngMode) == SOCKET_ERROR ) {					
				closesocket( pOvrl->m_sock );
				continue;
			}			

			//CreateIoCompletionPort( (HANDLE)pOvrl->m_sock, m_hIocp, (ULONG)&pOvrl->m_sock, 0 );		
			
			if ( pOvrl != NULL ) {			
				PostQueuedCompletionStatus(m_hIocp, 1, NULL, (OVERLAPPED*)pOvrl);
			}
		}		
	};	
	
	return true;
}

int CD2Class::Stop()
{	
	WSACleanup();
	CloseHandle(m_hIocp);

	Sleep(100);
	m_stop = 1;
	
	return true;
}

int CD2Class::IOCPThread(TIOCPParams * pParams)
{
	int nRet = 0, localstop = 0;
	void * pKey;
	TMYOVERLAPPED * pOvrl;
	DWORD dwBytesTransferred;
	DWORD error;
	TIOCPParams params = *pParams;

	SetEvent(m_threadEvent);
	Sleep(10);

	while ( ( m_stop == 0 ) && (localstop == 0) )
	{
		pKey = NULL;
		pOvrl = NULL;
		
		nRet = GetQueuedCompletionStatus(m_hIocp, &dwBytesTransferred, (ULONG*)&pKey, (OVERLAPPED **)&pOvrl, 5000);
		
		if(nRet == 0) {				
			
			error = GetLastError();
			if( error == WAIT_TIMEOUT ) {

				printf("thread #%u\r\n", params.m_ThreadNumber + 1);
				continue;
			}		
			
			if ( pOvrl == NULL )
				continue;
		}

		if (pOvrl->m_ovrl.hEvent != 0) {
			m_stop = m_stop;
		}

		//CloseHandle( (HANDLE)pOvrl->m_sock );
		closesocket( pOvrl->m_sock );
		delete pOvrl;
		
		m_Mutex.Lock();
		m_opcnt--;
		m_Mutex.Unlock();
	};
	
	return nRet;
}
_angry вне форума Ответить с цитированием
Старый 05.10.2012, 14:23   #2
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

Проверьте через 5 минут - возможно сокеты не сразу закрываются, ведь там же есть handshake с пиром
waleri на форуме Ответить с цитированием
Старый 05.10.2012, 16:11   #3
_angry
Новичок
Джуниор
 
Регистрация: 05.10.2012
Сообщений: 2
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
Проверьте через 5 минут - возможно сокеты не сразу закрываются, ведь там же есть handshake с пиром
Я понял бы, если бы хэндл закрылся и освободился, а в системе 5 минут была бы занята пара IP/порт. Но хэндл остается висеть бесконечно долго. Кроме того, если бы ваше предположение было верно, то после коннекта и дисконнекта с 1000 клиентов я получил бы 1000 повисших хэндлов.
Нет, здесь что-то именно с IOCP, т.к. если закрывать сокеты сразу после accept, т.е. в потоке, вызывающем accept, то никаких утечек нет.
_angry вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
утечка памяти Кудаив Помощь студентам 1 30.04.2012 18:18
Утечка памяти forivanb Общие вопросы Delphi 4 11.04.2012 15:28
Утечка памяти Juffin Общие вопросы Delphi 3 02.11.2010 12:11
Утечка памяти ZvEr_HaCkEr Свободное общение 13 24.09.2010 19:30
утечка памяти в С++ vengo Общие вопросы C/C++ 9 10.06.2008 21:24