inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

GetQueuedCompletionStatus() 에러 핸들링

875

erfrr
0

안녕하세요 현재 iocp로 게임 서버 구현 중에 있습니다.

제가 현재 고민 중인 부분은 GetQueuedCompletionStatus()에서 64에러(상대방이 소켓 종료)할 때 그 후처리에 관해 문제가 있어 문의 드립니다. 현재 서버에서 30틱 주기로 패킷을 브로드 캐스팅 중입니다. 이때 클라이언트를 종료할 경우, 기존에 send 명령이 들어있던 것들이 전부 false를 리턴하면서 저 스위치의 default 문에 들어가게 되고 Disconnect를 통해 unordered_map<int sid, SeverSession*>로 관리하고 있던 서버 세션을 맵에서 삭제하는 방식으로 진행하고 있습니다. 그런데 이 Disconnect부분에서 delete를 여러 번 수행하다 보니 여기서 더블딜리트 문제로 서버가 터져버리는 현상이 자꾸 발생합니다. 이점을 어떻게 개선하면 좋을까요...? shared_ptr를 사용해보려고 했다가, shared_ptr에 관한 이해가 부족해서 구조 변경을 실패했습니다..

전반적인 iocp 코드는 서버 강의를 들으면서 참고 했습니다.

-Disconnect 부분

void SIocpCore::Disconnect(int32 sid)
{
	if (_clients[sid] == nullptr || (_clients.find(sid) == _clients.end())) return;
	if(sid >= 0 && _clients[sid]->_myRm != -1) _rmgr->ExitRoom(sid, _clients[sid]->_myRm);
	{
		std::unique_lock<std::shared_mutex> disconnectLock(_lock);
		std::cout << "[" << _clients[sid]->_cid << "] Disconnected" << std::endl;
		_cList.erase(_clients[sid]->_cid);
		_clients.erase(sid);
	}
}

-GetQueuedCompletionStatus 에러 핸들링 부분

bool IocpCore::Processing(uint32_t time_limit) // worker thread 기능 완료된 비동기 통지 명령들을 받아와 적절하게 처리한다.
{
	DWORD numOfBytes(0); // 몇 바이트가 전송되었는가?
	IocpObject* iocpObject = nullptr; // 일감이 완료된 iocpObject의 종류를 복원하기 위한 IocpObject
	IocpEvent* iocpEvent = nullptr; // 일감이 완료된 iocpEvent의 종류(Accept인가?)
	
	BOOL retVal = ::GetQueuedCompletionStatus(_hIocp, OUT & numOfBytes, reinterpret_cast<PULONG_PTR>(&iocpObject), // 하지만 이렇게 iocpObject를 인자로 넘겨주게 되면, 다른 스레드에서 이 오브젝트를 삭제했을 때, 문제가 생길 수도 있다. --> 
		//애초에 iocpEvent에서 해당 iocp객체들에 관한 정보(해당 이벤트를 호출한 주인 iocp객체들)을 담고 있도록하자.
		OUT reinterpret_cast<LPOVERLAPPED*>(&iocpEvent), time_limit);
	
	if (!retVal) // 실패했다면 에러코드 확인
	{
		int32 errCode = ::WSAGetLastError();
		switch (errCode)
		{
			case WAIT_TIMEOUT: // time_limit이 INFINITE가 아닌 경우 ==> 나중에 다중 접속 시, 접속 시간에 따라 지정 가능
				std::cout << "Time Out Plz Check Your Network Condition" << std::endl;
				return false;
			default:
				// TODO : 로그 찍기 errcode는 64가 뜹니다.
			{
				std::cout <<  "GetQueuedError " << ::WSAGetLastError() << "\n";
				ServerSession* s = static_cast<ServerSession*>(iocpObject);
				Disconnect(s->_sid);
			}
			return false;
		}
	}
... // 성공 시 Processing 

답변 0