#include "stdafx.h"

#include <string>
#include <map>

// boost mpl 라이브러리
#include <boost/mpl/assert.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/at.hpp>

// boost function 라이브러리
#include <boost/function.hpp>

// boost bind 라이브러리
#include <boost/bind.hpp>

namespace mpl = boost::mpl;

// 패킷 타입 정의
enum PacketType : int
{
                 Login,
                 Logout,
                 SendData,
};

// 패킷 구조체 정의
struct STLogin
{
                std:: string                              strID;
                std:: string                              strPW;

                STLogin() : strID( "test"), strPW("Password" )               {}
};

struct STLogout
{
                std:: string                              strDesc;

                STLogout() : strDesc( "Logout")       {}
};

struct STData
{
                 int                                                           a;
                 int                                                           b;

                STData() : a(0), b(1)             {}
};

// 패킷 구조체
struct CPacket
{

};


// mpl map pair 타입
template< int N, class T >
struct Entry
{
                 typedef mpl::pair < mpl::int_< N >, T > type ;
};

// 패킷 타입과 패킷 구조체 pair 로 묶여 있는 mpl map
typedef mpl::map
<
                 Entry< Login , STLogin >:: type,
                 Entry< Logout , STLogout >:: type,
                 Entry< SendData , STData >:: type
>
PacketStructMap;

// 패킷 구조체 맵에서 구조체 타입 가져오기
template< class T, int N >
struct GetPacketStructType : mpl::at< T, mpl::int_ < N > >            {};

class CPacketDispatcher
{
public:

                 struct IHandler
                {
                                 virtual bool callFunc(CPacket* const _pPacket) = 0;
                };

                 template< class T >
                 class CPacketHandler : public IHandler
                {
                 private:

                                 typedef boost::function < bool( typename T&, CPacket * const) >               DeserializeFP;
                                 typedef boost::function < bool(typename T&) >                                                                             HandlerFP;

                                 DeserializeFP                                        m_fpDeserialize;
                                 HandlerFP                                                             m_fpHandler;

                                CPacketHandler();

                 public:

                                CPacketHandler( DeserializeFP _fpDeserialize , HandlerFP _fpHandler)
                                : m_fpDeserialize( _fpDeserialize)
                                , m_fpHandler( _fpHandler)
                                {}

                                 bool callFunc(CPacket * const _pPacket)
                                {
                                                 T             packetStruct;

                                                 if (m_fpDeserialize(packetStruct, _pPacket ))
                                                {
                                                                 return m_fpHandler(packetStruct);
                                                }

                                                 return false ;
                                }
                };

private:

                 // 패킷 핸들러들을 담아 놓을 맵
                 // boost::unordered_map 을 활용해도 좋다.
                 typedef std::map < int, IHandler* >                    PacketHandlerMap;
                 PacketHandlerMap                                                                                              m_mapPacketHandler;

public:

                 // 역 직렬화
                 template< int N, class T >
                 bool deserialize(T & _arg, CPacket* const _pPacket )
                {
                                 // 여기서 아래와 같이 패킷을 역직렬화를 통해 구조체를 뽑아낸다.
                                 // return _pPacket->deserialize(_arg);
                                 return true ;
                }

                 // 패킷 핸들러 Bind
                 template< int N >
                 void bindPacketHandler(boost::function < bool(typename GetPacketStructType<PacketStructMap , N>::type&) > _UserHandler )
                {
                                 // 패킷 구조체 타입
                                 typedef GetPacketStructType <PacketStructMap, N>::type                                                          STType;
                                 // 유저 정의 핸들러 타입
                                 typedef boost::function < bool( typename STType& ) >                                                               UserHandlerType;
                                 // 역직렬화 함수를 패킷 타입에 따라
                                 typedef boost::function < bool(typename STType&, CPacket * const) >                 DeserializeHandlerType;

                                 // 역직렬화 함수
                                 DeserializeHandlerType deserializeHandler    = boost::bind(&CPacketDispatcher ::deserialize< N, STType >, this, _1, _2);
                                 // 유저 핸들러
                                 UserHandlerType userHandler                                                                          = _UserHandler;

                                 // 패킷 핸들러 생성
                                 CPacketHandler< STType >* pPacketHandler = new CPacketHandler< STType >(deserializeHandler, userHandler);

                                 // 맵에 넣는다
                                m_mapPacketHandler.insert( PacketHandlerMap::value_type (N, pPacketHandler));                                
                }

                 // 패킷 처리
                 bool dispatchPacket(PacketType _ePacketType, CPacket* const _pPacket)
                {
                                 PacketHandlerMap::iterator itrF = m_mapPacketHandler.find(_ePacketType);
                                 if (itrF == m_mapPacketHandler.end()) return false;

                                 // 타입에 맞는 핸들러 실행
                                 return itrF->second->callFunc(_pPacket );
                }

                
};

// 사용자 정의 패킷 핸들러
struct user_packet_handler
{
                 bool login(const STLogin& _Login)
                {
                                 // 로그인 처리

                                 return true ;
                }

                 bool logout(const STLogout& _Logout)
                {
                                 // 로그 아웃 처리

                                 return true ;
                }

                 bool recvData(const STData& _Data)
                {
                                 // 데이터 처리

                                 return true ;
                }
};

int _tmain (int argc, _TCHAR* argv[])
{
                 // 패킷 처리기
                 CPacketDispatcher PacketDispatcher;

                 // 사용자 정의 핸들러
                 user_packet_handler UserHandler;

                 // 로그인 핸들러 등록
                PacketDispatcher.bindPacketHandler< Login>(boost::bind(&user_packet_handler ::login, &UserHandler, _1));
                 // 로그아웃 핸들러 등록
                PacketDispatcher.bindPacketHandler< Logout>(boost::bind(&user_packet_handler ::logout, &UserHandler, _1));
                 // 데이터 핸들러 등록
                PacketDispatcher.bindPacketHandler< SendData>(boost::bind(&user_packet_handler ::recvData, &UserHandler, _1));

                 // 잘못 등록했을 경우 컴파일 에러를 내뱉음
                 // PacketDispatcher.bindPacketHandler<Login>(boost::bind(&user_packet_handler::recvData, &UserHandler, _1));

                 //
                 // 패킷을 받았을 경우
                 CPacket packet;

                 // 로그인 처리
                PacketDispatcher.dispatchPacket( Login, &packet);
                 // 로그아웃 처리
                PacketDispatcher.dispatchPacket( Logout, &packet);
                 // 데이터 처리
                PacketDispatcher.dispatchPacket( SendData, &packet);

                getchar();

                 return 0;
}

패킷 타입을 정의함과 동시에 패킷 타입이 패킷 구조체를 갖게 된다. 

위의 예제에서는 수동으로 mpl::map 을 이용해서 타입과 구조체를 등록하게 되어 있는데 이부분은

PacketType을 헤더로 분리하고 간단한 파일 파싱을 통해 자동으로 구조체를 등록하게 하는 방법으로 할것인지

define을 이용해서 간단하게 처리할것인지 아직 고민중이다.

여기에는 없는 패킷의 직렬화/역직렬화 인데, 이전에 구현해뒀던 패킷 직렬화와 합쳐지면

패킷을 보내고 받는 절차가 지금 작업했던 방식에 비해 많이 줄어든다.
  

'Boost' 카테고리의 다른 글

Boost Assign 샘플  (0) 2016.01.29
Boost Array 샘플  (0) 2016.01.29
Boost Any 샘플  (0) 2016.01.29
boost - MPL 정리 중  (0) 2014.04.22
boost - meta state machine(1)  (0) 2014.04.22
      Boost  |  2014. 5. 26. 15:47



홍쿤사마's Blog is powered by Daum