6.Preparing for communication among hosts

넷텐션

먼저, Common 프로젝트에 C2S.PIDL, S2C.PIDL, C2C.PIDL을 만듭시다.

C2S.PIDL은 클라이언트에서 서버로 보내는 RMI, C2S.PIDL은 서버에서 클라이언트로 보내는 RMI, C2C.PIDL은 클라이언트간 P2P 통신을 하는 RMI입니다. 자세한 방법은 11. Usage of Remote Method Invocation에서 설명하고 있습니다.

그리고 나서 위 PIDL의 결과물인 proxy, stub을 각각 서버와 클라이언트에 붙이겠습니다.

(참고: 11. Usage of Remote Method Invocation)

C2S.PIDL

global C2S 3000 // client-to-server RMI, 1st Message ID = 3000
{
    Chat([in] CString a,[in] int b,[in] float c);
}

S2C.PIDL

global S2C 4000 // server-to-client RMI, 1st Message ID = 4000
{
    ShowChat([in] CString a,[in]int b,[in]float c);
    SystemChat([in] CString txt);
}

C2C.PIDL

global C2C 2000 // client-to-client RMI, 1st Message ID = 2000
{
    P2PChat([in] CString a,[in] int b, [in] float c);
}

클라이언트는 다음과 같은 include를 합니다.

#include "../common/vars.h"
#include "../common/C2S_common.cpp"
#include "../common/C2S_proxy.h"
#include "../common/C2S_proxy.cpp"

#include "../common/S2C_common.cpp"
#include "../common/s2C_stub.h"
#include "../common/S2C_stub.cpp"

#include "../common/c2c_common.cpp"
#include "../common/c2C_stub.h"
#include "../common/c2C_stub.cpp"
#include "../common/c2C_proxy.h"
#include "../common/c2C_proxy.cpp"

서버는 다음과 같은 include를 합니다.

#include "../common/vars.h"

#include "../common/C2S_common.cpp"
#include "../common/C2S_stub.h"
#include "../common/C2S_stub.cpp"

#include "../common/S2C_common.cpp"
#include "../common/S2C_proxy.h"
#include "../common/S2C_proxy.cpp"

그리고 나서 클라이언트에 다음과 같이 C2S의 Proxy, S2C의 Stub, C2C의 Proxy와 Stub을 붙입니다.

g_cli=Proud::CNetClient::Create();

g_cli->AttachProxy(&g_C2SProxy);
g_cli->AttachStub(&g_S2CStub);
g_cli->AttachProxy(&g_C2CProxy);
g_cli->AttachStub(&g_C2CStub);

서버는 다음과 같이 C2S의 stub, S2C의 proxy를 붙입니다.

CNetServer* srv=ProudNet::CreateServer();

srv->AttachStub(&g_C2SStub);
srv->AttachProxy(&g_S2CProxy);

6.1RMI stub 구현하기

RMI를 받아 처리하는 프로그램은 RMI stub을 구현할 필요가 있습니다.

먼저, 클라이언트에서는 S2C과 C2C의 RMI함수를 구현해야 합니다. 다음과 같이 구현하겠습니다. 아래 예시의 DECRMI_...와 DEFRMI_...는 매크로입니다. 이에 대한 설명은 Attaching Stub to client and server에 있습니다.

class C2CStub: public C2C::Stub   // RMI receiver class
{
public:
    DECRMI_C2C_P2PChat;   // RMI function C++ declaration
};

DEFRMI_C2C_P2PChat(C2CStub)   
{
    printf("[Client] P2PChat: a=%s,b=%d,c=%f\n", StringT2A(a), b, c);
    return true;
}

class S2CStub: public S2C::Stub
{
public:
    DECRMI_S2C_ShowChat;
    DECRMI_S2C_SystemChat;
};

DEFRMI_S2C_ShowChat(S2CStub)
{
    printf("[Client] ShowChat: a=%s,b=%d,c=%f\n", StringT2A(a), b, c);
    return true;
}

DEFRMI_S2C_SystemChat(S2CStub)
{
    printf("[Client] SystemChat: txt=%s\n", StringT2A(txt));
    return true;
}

서버에서는 C2S의 RMI함수를 구현해야 합니다. 다음과 같이 구현하겠습니다.

class C2SStub: public C2S::Stub
{
public:
    DECRMI_C2S_Chat;
};

DEFRMI_C2S_Chat(C2SStub)
{
    printf("[Server] Chat: a=%s,b=%d,c=%f\n", StringT2A(a), b, c);
    // echo to client
    g_S2CProxy.ShowChat(remote, RmiContext::ReliableSend, a, b + 1, c + 1);
    return true;
}

클라이언트에서는 다음과 같이 proxy,stub들을 인스턴스화합니다.

C2S::Proxy g_C2SProxy;
S2CStub g_S2CStub;
C2C::Proxy g_C2CProxy;
C2CStub g_C2CStub;

서버에서는 다음과 같이 proxy,stub들을 인스턴스화합니다.

C2SStub g_C2SStub;
S2C::Proxy g_S2CProxy;

참고: proxy와 stub은 반드시 전역 변수일 필요는 없습니다.