Boost Meta State Machine 의 위대함에 한참 넋을 놓고 파헤치고 있을때 뭔가 어딘가에 잘 써먹을 수 있어 


보이는 이벤트 처리 방법을 발견했습니다. 유레카!


그래서 일반적으로 서버 & 클라이언트의 통신 구조에서 주고받은 패킷 이벤트를 처리할 때 사용해보기로


마음먹었습니다.






#pragma once


//================================================================

/**

@author    skhong

@since     11/8/2014   14:39

@remarks   EventObject

  

*/

//================================================================


//

// Windows

//

#include <windows.h>


//

// boost

//

#include <boost/function.hpp>

#include <boost/bind.hpp>

#include <boost/foreach.hpp>


//

// VMEvent Object

//

#include "VMEventHandled.h"

#include "VMEventObject.h"


namespace VMFramework

{


namespace FCT

{


struct NONE

{

NONE(){}

NONE(CVMEventObject const&){}

};


} // namespace FCT


template <class EXEC,class CONDITION=FCT::NONE,class REJECT=FCT::NONE>

struct VMRow

{

typedef EXEC Execute;

typedef CONDITION   Condition;

typedef REJECT Reject;


typedef HandledEventEnum result_type;

HandledEventEnum exec_call( CVMEventObject const& _EventObject )

{

// create functor, call it

Execute()(_EventObject);

return HANDLED_EXEC_TRUE;

}


HandledEventEnum reject_call( CVMEventObject const& _EventObject )

{

// create functor, call it

Reject()(_EventObject);

return HANDLED_EXEC_REJECT;

}


BOOL cond_call( CVMEventObject const& _EventObject )

{

// create functor, call it

return Condition()(_EventObject);

}


HandledEventEnum operator()( CVMEventObject const& _EventObject )

{

// 성공하면 

if( TRUE == cond_call( _EventObject ) )

{

return exec_call( _EventObject );

}

else

{

return reject_call( _EventObject );

}


return HANDLED_EXEC_TRUE;

}

};


template<class EXEC,class CONDITION>

struct VMRow<EXEC,CONDITION,FCT::NONE>

{

typedef EXEC Execute;

typedef CONDITION Condition;

typedef FCT::NONE Reject;


typedef HandledEventEnum result_type;


HandledEventEnum exec_call( CVMEventObject const& _EventObject )

{

// create functor, call it

Execute()(_EventObject);

return HANDLED_EXEC_TRUE;

}


BOOL cond_call( CVMEventObject const& _EventObject )

{

// create functor, call it

return Condition()(_EventObject);

}


HandledEventEnum operator()( CVMEventObject const& _EventObject )

{

// 성공하면 

if( TRUE == cond_call( _EventObject ) )

{

return exec_call( _EventObject );

}


return HANDLED_EXEC_REJECT;

}

};


template<class CONDITION>

struct VMRow<FCT::NONE,CONDITION,FCT::NONE>

{

typedef FCT::NONE Execute;

typedef CONDITION Condition;

typedef FCT::NONE Reject;


typedef HandledEventEnum result_type;


BOOL cond_call( CVMEventObject const& _EventObject )

{

// create functor, call it

return Condition()(_EventObject);

}


HandledEventEnum operator()( CVMEventObject const& _EventObject )

{

// 성공하면 

if( TRUE == cond_call( _EventObject ) )

{

return HANDLED_EXEC_TRUE;

}


return HANDLED_EXEC_REJECT;

}

};


template<class CONDITION, class REJECT>

struct VMRow<FCT::NONE,CONDITION,REJECT>

{

typedef FCT::NONE Execute;

typedef CONDITION Condition;

typedef REJECT Reject;


typedef HandledEventEnum result_type;


BOOL cond_call( CVMEventObject const& _EventObject )

{

// create functor, call it

return Condition()(_EventObject);

}


HandledEventEnum reject_call( CVMEventObject const& _EventObject )

{

// create functor, call it

Reject()(_EventObject);

return HANDLED_EXEC_REJECT;

}


HandledEventEnum operator()( CVMEventObject const& _EventObject )

{

// 성공하면 

if( FALSE == cond_call( _EventObject ) )

{

return reject_call( _EventObject );

}


return HANDLED_EXEC_TRUE;

}

};



template<class EXEC,class REJECT>

struct VMRow<EXEC,FCT::NONE,REJECT>

{

typedef EXEC Execute;

typedef FCT::NONE Condition;

typedef REJECT Reject;


typedef HandledEventEnum result_type;


HandledEventEnum exec_call( CVMEventObject const& _EventObject )

{

// create functor, call it

Execute()(_EventObject);

return HANDLED_EXEC_TRUE;

}


HandledEventEnum reject_call( CVMEventObject const& _EventObject )

{

// create functor, call it

Reject()(_EventObject);

return HANDLED_EXEC_REJECT;

}


HandledEventEnum operator()( CVMEventObject const& _EventObject )

{

// 성공하면 

if( FALSE == cond_call( _EventObject ) )

{

return reject_call( _EventObject );

}


return HANDLED_EXEC_TRUE;

}

};


template<class EXEC>

struct VMRow<EXEC,FCT::NONE,FCT::NONE>

{

typedef EXEC Execute;

typedef FCT::NONE Condition;

typedef FCT::NONE Reject;


typedef HandledEventEnum result_type;


HandledEventEnum exec_call( CVMEventObject const& _EventObject )

{

// create functor, call it

Execute()(_EventObject);

return HANDLED_EXEC_TRUE;

}


HandledEventEnum operator()( CVMEventObject const& _EventObject )

{

return exec_call( _EventObject );

}

};


// 액션 시퀀스를 구현해보자

template <class Sequence>

struct VMExecSeq_

{

typedef Sequence sequence;

struct Call

{

Call(CVMEventObject const& _EventObject ):

EventObject_(_EventObject) {}


template <class FCT>

void operator()( FCT const& )

{

FCT()( EventObject_ );

}

private:

CVMEventObject const&  EventObject_;

};


HandledEventEnum operator()( CVMEventObject const& _EventObject )

{

boost::mpl::for_each< Sequence >( Call( _EventObject ) );


return HANDLED_EXEC_TRUE;

}

};


// 가드 Or 조건

template <class T1,class T2>

struct VMOr_

{

BOOL operator()( CVMEventObject const& _EventObject )

{

return (T1()(_EventObject) || T2()(_EventObject));

}

};


// 가드 And 조건

template <class T1,class T2>

struct VMAnd_

{

BOOL operator()( CVMEventObject const& _EventObject )

{

return (T1()(_EventObject) && T2()(_EventObject));

}

};



} // namespace VMFramework


위와 같이 템플릿 특수화를 이용해서 모든 조건에 동작 가능한 Event Functor 를 만들고 난 후


이벤트를 등록하기 쉽도록 한번더 랩핑했습니다.





#pragma once


//================================================================

/**

@author    skhong

@since     19/12/2014   15:09

@remarks   VMEvent Registration

  

*/

//================================================================


#include "VMEventFunctor.h"

#include "VMEventTable.h"


namespace VMFramework

{


template <class EXEC,class CONDITION=FCT::NONE,class REJECT=FCT::NONE>

struct VMEventRegistration

{

typedef EXEC Execute;

typedef CONDITION   Condition;

typedef REJECT Reject;

VMEventRegistration( CommonEvent::ID::Value _ID, CVMEventTable* const _Self  )

{

_Self->addEventRow( _ID, boost::bind( VMRow< Execute, Condition, Reject >(), _1 ) );

}

};


template<class EXEC,class CONDITION>

struct VMEventRegistration<EXEC,CONDITION,FCT::NONE>

{

typedef EXEC Execute;

typedef CONDITION   Condition;


VMEventRegistration( CommonEvent::ID::Value _ID, CVMEventTable* const _Self  )

{

_Self->addEventRow( _ID, boost::bind( VMRow< Execute, Condition >(), _1 ) );

}

};


template<class CONDITION>

struct VMEventRegistration<FCT::NONE,CONDITION,FCT::NONE>

{

typedef FCT::NONE Execute;

typedef CONDITION   Condition;

typedef FCT::NONE Reject;


VMEventRegistration( CommonEvent::ID::Value _ID, CVMEventTable* const _Self  )

{

_Self->addEventRow( _ID, boost::bind( VMRow< Execute, Condition >(), _1 ) );

}

};


template<class CONDITION, class REJECT>

struct VMEventRegistration<FCT::NONE,CONDITION,REJECT>

{

typedef FCT::NONE Execute;

typedef CONDITION   Condition;

typedef REJECT Reject;


VMEventRegistration( CommonEvent::ID::Value _ID, CVMEventTable* const _Self  )

{

_Self->addEventRow( _ID, boost::bind( VMRow< Execute, Condition, Reject >(), _1 ) );

}

};


template<class EXEC,class REJECT>

struct VMEventRegistration<EXEC,FCT::NONE,REJECT>

{

typedef EXEC Execute;

typedef FCT::NONE   Condition;

typedef REJECT Reject;


VMEventRegistration( CommonEvent::ID::Value _ID, CVMEventTable* const _Self  )

{

_Self->addEventRow( _ID, boost::bind( VMRow< Execute, Condition, Reject >(), _1 ) );

}

};


template<class EXEC>

struct VMEventRegistration<EXEC,FCT::NONE,FCT::NONE>

{

typedef EXEC Execute;

typedef FCT::NONE   Condition;

typedef FCT::NONE Reject;


VMEventRegistration( CommonEvent::ID::Value _ID, CVMEventTable* const _Self  )

{

_Self->addEventRow( _ID, boost::bind( VMRow< Execute, Condition, Reject >(), _1 ) );

}

};


} // namespace VMFramework



자 이제 이벤트를 등록하고 어떻게 사용하는지 보겠습니다.


VMEventRegistration

RoomEvtHandler::ReconnectMachine // 재접속 처리

>( CommonEvent::ID::C_Req_ReconnectMachine, _getEventTable() ); // 머신이 재접속을 요청한다.


패킷을 받고 연결할 콜백함수를 등록하는 방법입니다.


// 등록한 함수도 사실 함수객체 입니다.

struct ReconnectMachine { typedef void result_type; void operator()( VMEventObject const& _Evt ); };


오퍼레이터에 실제 동작 구현을 합니다.


실제 작업을 하다보면 이벤트를 받고 재접속 처리뿐만 아니라 사실을 더 많은 일을 해야합니다.


다른 예를 들자면


VMEventRegistration

<

VMExecSeq_< mpl::vector

<

GamePlayEvtHandler::RecvRoomScoreCard, // 룸 스코어 카드를 저장한다.

RoomEvtHandler::BroadcastRoomScoreCard, // 새롭게 입장 플레이어 데이터를 방안에 플레이어에게 전송해준다.

RoomEvtHandler::SendScoreCardListInRoom // 방안의 모든 스코어 카드를 전송한다.

> >

>( CommonEvent::ID::Inf_RoomScoreCard, _getEventTable() );     // 플레이어 데이터 받기


위와 같은 이벤트는 스코어 카드의 정보를 받고 3가지 동작을 순서대로 처리가 가능합니다.


여기서 한가지 더 나아가면 이벤트 등록과 함께 조건의 분기 처리도 가능해집니다.


VMEventRegistration

 // 방장일 경우(TRUE)

VMExecSeq_< mpl::vector

RoomEvtHandler::DestroyRoom, // 방장일시 방폭

RoomEvtHandler::SendUpdatedRoomForShopCode // 같은 매장내에 있는 머신에게 방 정보를 갱신시켜준다.

> >,


 // 이것은 조건문이 됩니다.

RoomEvtHandler::CheckRoomChief, // 방장 인가?


 // 방장이 아닐경우( FALSE )

VMExecSeq_< mpl::vector

RoomEvtHandler::LeaveRoom, // 방장아닐시 방 나가기

RoomEvtHandler::SendUpdatedRoomForShopCode // 같은 매장내에 있는 머신에게 방 정보를 갱신시켜준다.

> >

>( CommonEvent::ID::C_Req_Disconnect, _getEventTable() ); // 접속 종료 요청


위와같이 조건의 따른 분기 처리도 가능해집니다. VMExecSeq_ 의 갯수 제한도 사실상 없다고 보시면 됩니다.


VMEventRegistration

 // 방장일 경우(TRUE)

FCT::NONE,                                                          // 아무것도 처리하지 않는다.


 // 이것은 조건문이 됩니다.

RoomEvtHandler::CheckRoomChief, // 방장 인가?


 // 방장이 아닐경우( FALSE )

VMExecSeq_< mpl::vector

RoomEvtHandler::LeaveRoom, // 방장아닐시 방 나가기

RoomEvtHandler::SendUpdatedRoomForShopCode // 같은 매장내에 있는 머신에게 방 정보를 갱신시켜준다.

> >

>( CommonEvent::ID::C_Req_Disconnect, _getEventTable() ); // 접속 종료 요청


TRUE 경우 아무것도 처리하고 싶지 않을때는 NONE 함수를 등록해 주면 됩니다.



VMEventRegistration

 // 방장일 경우(TRUE)

FCT::NONE,                                                          // 아무것도 처리하지 않는다.


 // 이것은 조건문이 됩니다.

      VMAnd_

 < 

RoomEvtHandler::CheckRoomChief, // 방장 인가?

RoomEvtHandler::IsGamePlay      // 플레이 중인가?

 >,


 // 방장이 아닐경우( FALSE )

VMExecSeq_< mpl::vector

RoomEvtHandler::LeaveRoom, // 방장아닐시 방 나가기

RoomEvtHandler::SendUpdatedRoomForShopCode // 같은 매장내에 있는 머신에게 방 정보를 갱신시켜준다.

> >

>( CommonEvent::ID::C_Req_Disconnect, _getEventTable() ); // 접속 종료 요청


조건문의 조금더 복잡한 조건을 사용하고 싶을 때는 위와 같이 VMAnd_ 를 또는 VMOr_ 를 사용해 가능합니다.


서버 & 클라이언트 모델 뿐 만 아니라 실질적으로 시스템과 시스템, 스레드와 스레드, 컨텐츠와 컨텐츠 간의 통신 또는 이벤트를


처리 할 경우에도 매우 유용하게 사용할 수 있습니다.


일부 코드는 프로젝트에 맡게 수정하셔야 합니다 소스코드 첨부합니다.



패킷 처리기.zip










      C++  |  2016. 2. 1. 00:47



홍쿤사마's Blog is powered by Daum