4.Remote Method Invocation (원격 메서드 호출)

일반적으로 RMI는 네트워크 프로그램을 제작시 개발자를 힘들게 하는 프로그래밍 작업 (메시지 구조체 정의, 송신 함수, 수신 함수 작성)을 함수 호출의 형태로 간소화하는 역할을 합니다. 따라서 RMI를 사용할 경우 프로그래밍 작업 시간을 단축할 뿐만 아니라 네트워크 송수신 루틴의 작성 중 발생할 수 있는 실수를 없앨 수 있습니다.

4.1RMI를 사용하지 않을 경우의 프로그램의 예

// Message header ID definitions
#define Message_Knight_Move_ID 12
#define Message_Knight_Attack_ID 13

// Message format definitions
struct Message
{
    int m_msgID;
};
struct Message_Knight_Move:public Message
{
    int m_id;
    float m_x,m_y,m_z;
};
struct Message_Knight_Attack:public Message
{
    int m_id;
    int m_target;
    int m_damage;
};

// A function which send a formatted message
void Knight_Move(int id,float x,float y,float z)
{
    Message_Knight_Move msg;
    msg.m_msgID=Message_Knight_Move_ID;

    msg.m_id=id;
    msg.m_x=x;
    msg.m_y=y;
    msg.m_z=z;

    Send(msg);
}

// A function which send a formatted message
void Knight_Attack(int id,int target,int damage)
{
    Message_Knight_Attack msg;
    msg.m_msgID=Message_Knight_Attack_ID;

    msg.m_id=id;
    msg.m_target=target;
    msg.m_damage=damage;

    Send(msg);
}

// Identified a received message 
// and call an appropriate function for message handling
void DoReceivedMessage(Message* msg)
{
    switch(msg->m_msgID)
    {
    case Message_Knight_Move_ID:
    {
        Message_Knight_Move* msg2=
            (Message_Knight_Move*)msg;

        Do_Knight_Move(
            msg2->m_id,
            msg2->m_x,
            msg2->m_y,
            msg2->m_z);
    }
    break;
    // ... cases for other message types
    case Message_Knight_Attack_ID:
    {
        Message_Knight_Attack* msg2=
            (Message_Knight_Attack*)msg;

        Do_Knight_Attack(
            msg2->m_id,
            msg2->m_target,
            msg2->m_damage);
    }
    break;
    // ... cases for other message types
    }
}

하지만 RMI를 쓰면 위와 같은 프로그램을 작성할 필요가 없이 아래와 같은 짧은 코드로 끝이 납니다.

Knight_Move([in] int id,[in] float x,[in] float y,[in] float z);
Knight_Attack([in] int id,[in] int target,[in] int damage);

위 형식은 IDL(Interface Description Language) 형식의 언어입니다. 위 형식의 언어를 컴파일하면 C++ 소스가 만들어집니다. 만들어진 소스 파일은 메시지 구조체 선언, 송신 함수, 수신 처리 함수 등으로 이루어져 있습니다. 즉, 개발자가 직접 네트웍 처리 루틴을 만들지 않고, PIDL컴파일러(ProudNet IDL)가 자동으로 생성해 줍니다!

그림 4-1모든 것을 자동화하는 것은 애자일 개발에서의 미덕이기도 합니다.

여기서 우리는 몇 가지 용어를 이해해야 합니다. 앞서 IDL 파일을 컴파일하면 생성되는 파일들이 있다고 언급했는데, 그 파일 중 함수 호출을 메시지로 바꾸어 네트웍으로 보내는 모듈을 proxy라고 부르며 네트웍을 통해 받은 메시지를 분석해서 유저 함수를 호출하는 모듈을 stub이라고 부릅니다.

즉, 호스트 A에서 RMI 함수 X를 호출하면, 실제로 X의 proxy가 호출되며 proxy는 네트웍 메시지로 바꾸어 그것을 호스트 B로 보냅니다. 그리고 호스트 B는 메시지를 받아 stub에 보내며, stub은 분석을 한 후 유저가 작성한 함수 X를 호출합니다.

그림 4-2RMI 처리 순서

결국, 겉으로 보기에는 호스트 A에서 호스트 B에 있는 함수를 호출하는 것과 비슷한 모양을 가집니다. 그래서 Remote Method Invocation(원격 메서드 호출)이라는 의미를 갖게 된 것입니다.

4.2ProudNet의 RMI 시스템의 특성

기존에 통용되는 IDL 형식이나 RMI 시스템은 게임에 사용하기에는 너무 무겁고 느립니다. 그렇기 때문에 ProudNet은 자체 개발된 Remote Method Invocation(RMI) 시스템을 보유하고 있습니다.

게임 개발에서는 비동기 RMI, 즉 함수 호출 리턴값을 대기하지 않는 RMI가 거의 모든 경우 사용됩니다. 그렇기 때문에 ProudNet은 비동기 RMI만을 지원합니다.