LOGIN • JOININ

MESSAGE MEDIATING

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



1... 메시지 중계기(Message Mediator)란?

메시지 처리를 이임 받아 처리기 역할을 하는 것을 메시지 중계기(Message Mediator)라고 합니다.

Group에 있는 Socket의 경우 메시지를 Socket별로 처리하는 것이 아니라 메시지를 Group이 전달받아 처리하도록 하면 프로그램이 직관적이고 편리해집니다. (자세한 설명은 Group과 Message Mediating에 관한 문서 참조)


이 예제에서는 Group을 단순히 소켓들을 관리하는 관리기가 아니라 Member들의 메시지 처리를 Group이 전달 받아 처리하는 메시지 중계기 역할을 하도록 구현합니다.



2... Socket이 받은 메시지 중계기(Mediator)로 전달하기

Socket이 메시지를 전달받게 되면 Group에 메시지를 전달하도록 하기 위해서

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;
};

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

	return	0;
}

1) Socket은 NCGDispatchable 클래스를 상속받습니다.  이 클래스는 메시지를 전달할 곳을 등록해 전달할 수 있습니다.

(엄밀히 말해서 굳이 NCGDispatchable을 상속받을 필요 없이 중계기에 대한 포인터 하나만 가지면 됩니다. )

2) OnMessage()함수에서 메시지를 전달받으면 NOTIFY_MESSAGE_SOURCE(…)를 사용해 메시지를 등록된 객체로 메시지를 전송합니다.
(그냥 중계기에 대한 포인터만 가지도록 했다면 중계기의 RequestProcessMessage(...)함수를 호출해주면 됩니다.)



3... Group에서 메시지 받기

Group에 입장한 Socket들의 메시지를 처리를 전달받아 처리하기 위해서 Group이 Messageable 클래스를 상속받습니다.
쉽게 말해서 Socket과 같은 OnMessage(...)함수를 가지도록해서 메시지를 처리하도록 한다는 것입니다.
Group에 메시지를 전달받아 처리하기 위해서 다음과 같은 처리를 해줍니다.


① Grouop이 Message를 받기 위해 ‘ICGMessageable’인터페이스 클래스를 상속받습니다.

② 새로운 Member가 입장하게 되면 메시지 전달처로 Group 자신으로 설정하게 합니다.

③ Member가 퇴장하게 되면 메시지 전달처로 등록했던 것을 해제합니다.


class CGroup : 
	public CGServerGroup::CListSender<CSocket>,
	public	CGNet::IO::Messageable::NBase // 1) Message Mediator
{
protected:
	virtual	void	OnMemberEntered(CSocket* _pMember, CGMSG& /*_MSG*/) override	
	{
		// 2) 새로운 Member가 들어오면 this를 메시지 전달처로 등록한다.
		_pMember->RegisterMessageable(this);
	}

	virtual	uintptr_t OnMemberLeaving(CSocket* _pMember) override
	{
		// 3) Member가 나가면 메시지 전달처에서 등록해제한다.
		_pMember->UnregisterMessageable(this);
		return	0;
	}

	virtual int	OnMessage(CGMSG& /*_MSG*/)
	{
		// 4) 여기서 Message를 처리한다.
		printf("Message Received!\n");
		return	0;
	}
};

1) 메시지를 전달받기 위해 ‘CGNet::IO::Messageable::NBase’를 상속받았습니다.

2) 새로운 Member가 입장하면 메시지 전달지로 this를 설정합니다.

3) Member가 퇴장하면 메시지 전달지로 등록했던 것을 해제합니다.

4) OnMessage()함수를 정의해 메시지가 전달되어 오면 처리합니다.


또 Socket은 OnMessage()함수로 메시지를 전달받으면 그것을 바로 자신의 Group에 바로 전달해 주면 됩니다.



[TutorialGroupServerMessageMediator.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 // 1) Message Mediator
{
protected:
	virtual	void	OnMemberEntered(CSocket* _pMember, CGMSG& /*_MSG*/) override	
	{
		// 2) 새로운 Member가 들어오면 this를 메시지 전달처로 등록한다.
		_pMember->RegisterMessageable(this);
	}

	virtual	uintptr_t OnMemberLeaving(CSocket* _pMember) override
	{
		// 3) Member가 나가면 메시지 전달처에서 등록해제한다.
		_pMember->UnregisterMessageable(this);
		return	0;
	}

	virtual int	OnMessage(CGMSG& /*_MSG*/)
	{
		// 4) 여기서 Message를 처리한다.
		printf("Message Received!\n");
		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;
}