LOGIN • JOININ

GROUP WITH EXECUTABLE

[Tutorials/[Server] 1. Group classes/Sever/Tutorial_GroupServer03_Execute]



1... 일정 시간마다 특정 함수 호출하기

Group단위로 일정시간마다 주기적으로 특정한 처리를 해줘야 하는 경우가 있습니다.

특히 게임에서 게임의 진행등을 위해 Group 단위의 Schedulable은 매우 빈번히 사용됩니다.

보통 이런 것을 구현하기 위해서는 쓰레드를 사용해 복잡한 처리를 해주어야 하지만  Group에 ICGSchedulable를 상속받은 다음 Scheduler에 등록만 하면 손쉽게 이런 기능 구현을 간단하게 구현할 수 있습니다.

(Schedulable에 대한 자세한 내용은 ‘CGCII @2 기본-쓰레드’편을 참조)



2... Group에 ICGSchedulable 클래스 상속 받기

Group단위로 일정시간마다 주기적으로 특정한 처리를 해 줘야 하는 경우가 있습니다.

이를 위해 Group이 ICGSchedulable 클래스를 구현한 CGSchedulable::NExecutable을 상속받아 Scheduler에 등록하면 됩니다.

class CGroup : 
	public CGServerGroup::CListSender<CSocket>,
	public CGNet::IO::Messageable::NBase,
	public CGSchedulable::NExecutable		// @1) Executable!!!
{
protected:
	// @2) Executable!!! (*)
	virtual	HRESULT ProcessExecute(_In_ uintptr_t _Return, _In_ size_t _Param) 
	{
		printf("Executed!\n");
		return	0;
	}

	virtual	void	OnMemberEntered(CSocket* _pMember, CGMSG& /*_MSG*/);
	virtual	uintptr_t OnMemberLeaving(CSocket* _pMember) override;

	. . .
};

1) 먼저 ‘CGSchedulable::NExecutable’을 상속받습니다.

2) ProcessExecut()함수를 재정의합니다. 이 함수는 Schedulable에 등록되면 설정된 간격마다 실행됩니다.


여기에 일정 시간마다 처리될 내용을 작성하면 됩니다.



3... Group을 Scheduler에 등록하기

void CGroup::OnMemberEntered(CSocket* _pMember, CGMSG& /*_MSG*/) override	
{
	// @3) 첫 Member가 Enter할 경우...
	if(GetMemberCount()==1)
	{
		// - 실행될 간격을 설정한다.(5초로 설정)
		SetExecuteInterval(TICK::SECONDS(5));

		// - Executor에 현재 Group을 붙인다.
		REGISTER_SCHEDULABLE(this);
	}

	_pMember->RegisterMessageable(this);
}

uintptr_t CGroup::OnMemberLeaving(CSocket* _pMember) override
{
	// @4) 마지막 Member가 나가는 경우
	if(GetMemberCoount()==1)
	{
		// - Group을 Executor에서 떼낸다. (이후 ProcessExecute()함수는 호출되자 않는다.)
		UNREGISTER_SCHEDULABLE(this);
	}

	_pMember->UnregisterMessageable(this);
	return	0;
}

3) 첫 Member가 입장하면 Group을 Scheduler에 붙혀서 일정시간마다 ProcessExecute()가 호출되도록 합니다. 

여기서는 실행간격은 ‘5초’로 설정해 Scheduler에 등록시켰습니다.

4) 마지막 Member가 퇴장하게 되면 Group을 Scheduler에서 떼어냅니다. 


만약 최초 입장 시 Schedulable에 등록시키는 것이 아니라 Group을 Start할 때 등록하고 Close할 때 해제하고 싶다면 OnStart()에서 Schedulable에 등록하고 OnStop()에서 등록해제하면 될 것입니다. 언제든 Schedulable에 등록하면 설정한 대로 일정 간격마다 실행이 되며 등록 해제하면 실행을 하지 않습니다.



[TutorialGroupServerSchedulable.cpp]
#include "stdafx.h"
#include "CGServerGroupTemplates.h"


class CSocket :
	public	CGNet::Socket::CTCP<>,
	public	ICGServerGroupable<CSocket>,
	public	NCGDispatchable			// @1) 이것을 추가로 상속받음!
{
private:
	virtual void	OnConnect() override;
	virtual void	OnDisconnect(uint32_t p_Reason) override;
	virtual	int		OnMessage(CGMSG& _MSG) override;
};

class CGroup : 
	public CGServerGroup::CListSender<CSocket>,
	public CGNet::IO::Messageable::NBase,
	public CGSchedulable::NExecutable		// @1) Executable!!!
{
protected:
	// @2) Executable!!! (*)
	virtual	HRESULT ProcessExecute(_In_ uintptr_t /*_Return*/, _In_ size_t /*_Param*/) override
	{
		printf("Executed!\n");
		return	0;
	}

	virtual int	OnMessage(CGMSG& /*_MSG*/)
	{
		printf("Message Received!\n");
		return	0;
	}

	virtual	void	OnMemberEntered(CSocket* _pMember, CGMSG& /*_MSG*/) override;
	virtual	uintptr_t OnMemberLeaving(CSocket* _pMember) override;
};

void CGroup::OnMemberEntered(CSocket* _pMember, CGMSG& /*_MSG*/)
{
	// @3) 첫 Member가 Enter할 경우...
	if(GetMemberCount()==1)
	{
		// - 호출될 간격을 설정한다.(5초로 설정)
		SetExecuteInterval(TICK::seconds(5));

		// - Executor에 현재 Group을 붙인다.
		REGISTER_SCHEDULABLE(this);
	}

	_pMember->RegisterMessageable(this);
}

uintptr_t CGroup::OnMemberLeaving(CSocket* _pMember)
{
	// @4) 마지막 Member가 나가는 경우
	if(GetMemberCount()==1)
	{
		// - Group을 Executor에서 떼낸다. (이후 ProcessExecute()함수는 호출되자 않는다.)
		UNREGISTER_SCHEDULABLE(this);
	}

	_pMember->UnregisterMessageable(this);
	return	0;
}

CGPTR<CGroup>	g_pgroupRoom;

void CSocket::OnConnect()
{
	g_pgroupRoom->EnterMember(this);
}

void CSocket::OnDisconnect(uint32_t /*p_Reason*/)
{
	LeaveGroup();
}

int CSocket::OnMessage(CGMSG& _MSG)
{
	// 1) 전달된 메시지를 바로 Group에 전달한다.
	NOTIFY_MESSAGE_SOURCE(_MSG, this);

	return	0;
}

int _tmain(int /*argc*/, _TCHAR* /*argv*/[])
{
	// 1) Group 객체를 생성한다.
	g_pgroupRoom	 = NEW<CGroup>();

	// 2) Group의 Enter가 가능하도록 한다.
	g_pgroupRoom->EnableEnter();

	// 3) Acceptor 객체를 생성한다.
	auto	pacceptor	 = NEW<CGNet::CAcceptor<CSocket>>();

	// 4) 10000번 포트에 Listen을 시작한다.
	pacceptor->Start(10000);

	// 5) ESC키를 누를 때까지 대기한다.
	while(_getch()!=27);

	// 6) Acceptor를 닫는다.
	pacceptor->Stop();

	return 0;
}