RMI

ProudNet은 자체 개발된 Remote Method Invocation(RMI) 시스템으로, 기존에 통용되는 IDL 형식이나 RMI 시스템보다 훨씬 빠르고 가벼우며 게임 개발에서는 '함수 호출 리턴값'을 비동기 RMI만 지원합니다.

RMI 함수 그룹

0개 이상의 RMI 함수 집합으로, PIDL 파일에서는 global 구문 블럭의 형태입니다.

global SimpleC2S
{
    ...;
}

Proxy에서 RMI 함수를 호출하면 즉시 리턴합니다. 그리고 RMI 함수 실행 결과를 Proxy 측에서 기다렸다가 받지는 못합니다.

RMI 메서드 인자 속성

메서드 인자에는 속성 정의가 들어가며 각 파라미터마다 한 개 이상 쓸 수 있습니다.

in : 입력 형식의 인자임을 의미하며 반드시 사용해야 합니다. 현재 버전에서는 'out'을 지원하지 않습니다.

// 예를 들어, 다음과 같이 RMI 메서드를 선언하면 
Test([in] Proud::String a,[in] int b,[in] float c);

// 다음과 같은 C++ code가 생성됩니다.
Test(Proud::HostID remote, Proud::RmiContext& rmiContext, const Proud::String& a, const int& b, const float& c);

대부분의 경우 RMI 메서드의 인자의 속성은 in 만을 사용합니다.

- byval 속성

인자가 by value로 전달됨을 의미하며 이것이 사용되면 C++ proxy 및 stub에서 인자 형식에 & 부호가 생략됩니다. int나 float 등 인자 형식에 크기가 작은 형식에 적합합니다.

// RMI 함수를 이렇게 선언하면,
Foo([in] int a);

// 생성되는 C++ Proxy and Stub에는 함수 파라미터가 by reference로 전달됩니다. 
// 아래 const int& a가 그것입니다.
SimpleC2S.Foo = [](Proud::HostID from, Proud::RmiContext& rmiContext, const int& a) = { ... };

// RMI 함수를 이렇게 byval 속성을 추가해서 선언하면,
Foo([in, byval] int a);

// 이렇게 by value로 형태로 만들어집니다.
SimpleC2S.Foo = [](Proud::HostID from, Proud::RmiContext& rmiContext, int a) = { ... };

- mutable 속성

인자가 const type이 아님을 의미하며 이것이 사용되면 C++ proxy 및 stub에서 인자 형식에 const 키워드가 생략됩니다. RMI stub에서 받은 인자의 값을 변경하고자 할 때 적합합니다.

// 이렇게 mutable 속성을 추가하시면
Foo([in, mutable] int a);

// 이렇게 변경 가능한 변수로 변경됩니다. const가 사라져 있을 것입니다.
SimpleC2S.Foo = [](Proud::HostID from, Proud::RmiContext& rmiContext, int& a) = { ... };

이종 언어로 된 프로그램 간 통신하기

두 프로그램이 ProudNet으로 통신하되 서로 다른 프로그래밍 언어로 만들고 싶을 때가 있습니다. 이러한 경우 PIDL 컴파일러는 두 개 이상의 언어로 된 proxy와 stub을 생성한 후 각 프로그램은 필요한 것을 가져다 쓰면 됩니다.

int, double, string 등 기본 타입에 대해서는 ProudNet의 C++ 외의 언어를 위한 래핑 모듈에서 이미 제공하고 있습니다. 하지만 언어가 서로 다르면 이러한 기본 타입의 이름이 기본적으로 달라지기 마련입니다. 예를 들어 C# 은 문자열 클래스가 System.String 인데, C++에서는 std::string, std::wstring, ATL::CString, Proud::String입니다.

이를 해결하기 위해 PIDL 컴파일러는 사용자가 원할 경우 생성되는 proxy, stub에서 변수 타입을 특정 언어에 한해서 변경하는 기능을 제공하고 있습니다.

아래는 사용 예입니다.

rename cs(TypeA,TypeB);     // 1
 
rename cpp(TypeC,TypeD);    // 2
 
global XXX 2000
{
    Foo([in]TypeA a);  // 3
    Goo([in]TypeC c);  // 4
}

RMI 메시지 범위

각 RMI 함수 선언은 1개의 메시지 타입을 가집니다. ProudNet의 메시지 타입은 6만 이하의 범위에서 사용자가 결정하며 이 범위는 사용자가 .pidl 파일을 작성시에 합니다.

1.7.42965-master 미만의 버전에서는 1,300 ~ 60,000 범위의 값을 사용하셔야 됩니다.

각 RMI의 메시지 타입 값의 예는 아래와 같습니다.

global SampleRMI 2000
{
    Foo1(...); // Assigned Message Type ID = 2001
    Foo2(...); // Assigned Message Type ID = 2002
    Foo3(...); // Assigned Message Type ID = 2003
}

각각의 함수는 메시지 타입 값이 하나씩 증가합니다. 그리고 마지막으로 선언된 RMI 함수에 배정된 타입 값까지를 메시지 범위라고 칭하겠습니다. 위의 예시에서 2,000 ~ 2,003이 SampleRMI를 위한 메시지 범위입니다.

생성된 Proxy와 Stub을 Proud.CNetClient , Proud.CNetServer , Proud.CLanClient , Proud.CLanServer 에 attach 하면 각 RMI function group 들의 메시지 범위가 Proud.CNetClient , Proud.CNetServer , Proud.CLanClient , Proud.CLanServer 에 예약됩니다.

만약 attach 할 proxy와 stub들의 메시지 범위가 겹치는 것들이 있으면 AttachProxy()AttachStub() 은 exception을 발생시킬 것입니다.

C#에서 CNetClient -> NetClient

C#에서 CNetServer -> NetServer


활용

Last updated