게임서버

게임서버) 11. IOCP Core

PJNull 2023. 1. 17.
728x90
반응형

IOCP Core

 

이제 IOCP모델을 서버코어에 넘겨주어야 하기 떄문에 세분화 하여 정리할 필요가 있다.

 

IOCP의 핵심 요약

 

  • CreateIocompletionport를 사용하여 (초기화된)CP큐를 생성한다.
  • CP에 연결할 객체(Object)를 생성한다.
  • CreateIocompletionport를 이용하여 생성한 객체를 CP에 등록한다(관찰대상 등록)
  • WSARecv를 사용하여 WorkerThread에게 전송을 맡긴다(이때 WorkerThread에서 마지막에 WSARecv를 호출해야된다)

 

 

IOCP Core

 

IOCP모델의 CP큐를 담당하는 클래스이다.

 

//IOCPCore.h


class IocpObject : public enable_shared_from_this<IocpObject>
{
public:
	

	virtual HANDLE GetHandle()abstract;
	virtual void Dispatch(class IocpEvent* iocpEvent, int32 numOfBytes = 0) abstract;
	
};
//CP에 연결할 관찰대상을 상속시키기 위한 클래스


class IocpCore	//CP큐
{
	IocpCore();
	~IocpCore();


	HANDLE GetHandle() { return _iocphandle; }
    
	bool Register(shared_ptr<locpObject> iocpObject);
	//Session이나 Object를 CP큐에 등록<-CreateIoCompletionPort
    
	bool Dispatch(uint32 timeoutMs=INFINITE);
	//워커쓰레드들이 일감을 꺼내가는 함수<-GetQueueCompletionStatus
    
    private:
	HANDLE _iocphandle;
}

 

//IOCPCore.cpp

IocpCore::IocpCore()
{
	_iocphandle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
    //(초기화된)CP큐를 생성
	assert(_iocphandle!= INVALID_HANDLE_VALUE);
}

IocpCore::~IocpCore()
{
	::CloseHandle(_iocphandle);
}

bool IocpCore::Register(shared_ptr<IocpObject> iocpObject)
{
	return	::CreateIoCompletionPort(iocpObject->GetHandle(),_iocphandle,0,0);;
			//오브젝트를 CP에 등록(관찰대상으로 등록)
}

bool IocpCore::Dispatch(uint32 timeoutMs)
{
	DWORD numOfbyte = 0;
   	ULONG_PTR key = 0;
	shared_ptr<IocpObject> iocpobj = nullptr;//Cp큐에 등록할 오브젝트
	IocpEvent* iocpevnt = nullptr;//특정이벤트 구분을 위한 IocpEvent객체
	
	
	
	if (::GetQueuedCompletionStatus(_iocphandle, OUT & numOfbyte, OUT static_cast<PULONG_PTR>(&key), OUT reinterpret_cast<LPOVERLAPPED*>(&iocpevnt), timeoutMs))
	{
    		iocpobj = iocpevnt->owner;//RefCount를 위해서
		iocpobj->Dispatch(iocpevnt, numOfbyte);
	}
	 	
	else
	{
		int32 err = ::WSAGetLastError();
		switch (err)
		{
		case WAIT_TIMEOUT:
			return false;
		default:
        		iocpobj = iocpevnt->owner;//RefCount를 위해서
			iocpobj->Dispatch(iocpevnt,numOfbyte);
			break;
		}
	}
	return false;
}

 

 

IOCP Event

 

IOCP모델은 Overlapped모델을 확장한 모델이다. Overlapped모델에서는 특정한 이벤트들을 구분하고 처리해주는 역할을 했었는데, 이러한 부분들을 처리해줄 클래스가 바로 IOCP Event부분이다.

 

//IOCPEvent.h

class Session;

enum class EventType :uint8
{
	Connect,
	Disconnect,
	Accept,
	Recv,
	Send,

};

class IocpEvent
{
public:
	OVERLAPPED overlapped = {};


	IocpEvent(EventType type);
	void Init();
	
    	shared_ptr<Session> owner=nullptr;

	EventType _type;
	shared_ptr<Session> session = nullptr;
};
//IOCPEvent.cpp

IocpEvent::IocpEvent(EventType type):_type(type)
{
	Init();
}

void IocpEvent::Init()
{
	overlapped.hEvent = 0;
	overlapped.Internal = 0;
	overlapped.InternalHigh = 0;
	overlapped.Offset = 0;
	overlapped.OffsetHigh = 0;

}

 

 

NetAddress

 

번잡하게 관리될수 있는 IP주소를 맵핑하고 관리하는 클래스이다.

 

//NetAddress.h


class NetAddress
{
public:

	NetAddress()=default;
	NetAddress(SOCKADDR_IN sockAddr);
	NetAddress(std::wstring ip,uint16 port);
	
	SOCKADDR_IN&	GetSockAddr() { return _sockAddr; }
	std::wstring	GetIpAddress();
	uint16			Getport() { return ::ntohs(_sockAddr.sin_port); }

public:
	static IN_ADDR Ip2Address(const WCHAR* ip);
private:
	SOCKADDR_IN _sockAddr = {};

};
//NetAddress.cpp

NetAddress::NetAddress(SOCKADDR_IN sockAddr):_sockAddr(sockAddr)
{
}

NetAddress::NetAddress(wstring ip, uint16 port)
{
	::memset(&_sockAddr,0,sizeof(_sockAddr));
	_sockAddr.sin_family = AF_INET;
	_sockAddr.sin_port = ::htons(port);
	_sockAddr.sin_addr = Ip2Address(ip.c_str());
}

std::wstring NetAddress::GetIpAddress()
{
	WCHAR buffer[100];
	::InetNtopW(AF_INET, &_sockAddr.sin_addr, buffer, len32(buffer));
	return wstring(buffer);
}

IN_ADDR NetAddress::Ip2Address(const WCHAR* ip)
{
	IN_ADDR address;
	::InetPtonW(AF_INET, ip, &address);
	return address;
}

 

 

 

4.Listener:관찰대상..?

 

 

728x90
반응형

댓글