RMI 활용법

RMI 함수별로 ID 개별 지정하기

global {} 안에 있는 RMI 함수들은 일련 값의 RMI ID 가 배정됩니다.

원하는 RMI ID 값을 가지게 하기 위해서는 아래의[id=xxx] 구문을 참고합니다.

global MedivalWorld 10000
{
    Foo([in] int x);                   // id=10001 자동 지정
    [id=13000] id=Foo2([in] int y);    // id=13000으로 강제 지정
}

과거 송수신 처리 방식 유지하기

과거의 송수신 처리 방식으로 만들어진 프로그램에 ProudNet을 도입할 때, RMI 방식으로 바꾸는 것을 권장합니다. 프로그래머가 송수신 루틴을 잘못 만드는 실수를 방지하고 추후 개발이 더욱 편리합니다.

하지만 RMI가 아닌 과거의 송수신 처리 방식이 꼭 필요하다면 다음과 같은 대안을 제시해 드립니다.

- RMI 없이 사용자 정의 메시지를 주고 받기

Remote Method Invocation(원격 메서드 호출) 를 쓰지않고 사용자가 정의한 메시지를 송신하기 위해 다음과 같은 함수를 이용합니다.

송신수신 콜백

Proud.CNetClient.SendUserMessage

Proud.INetClientEvent.OnReceiveUserMessage

Proud.CNetClient.SendUserMessage

Proud.INetServerEvent.OnReceiveUserMessage

Proud.CLanClient.SendUserMessage

Proud.ILanClientEvent.OnReceiveUserMessage

Proud.CLanServer.SendUserMessage

Proud.ILanServerEvent.OnReceiveUserMessage

- RMI의 파라미터로 사용자 정의 메시지를 주고 받기

// ProudNet에서는 Proud.ByteArray 타입을 
// RMI의 파라미터로 다음과 같이 사용할 수 있습니다.
Foo([in] Proud::ByteArray something);

// --- 여기까지 PIDL

// 이를 활용해서 과거의 송수신 처리 루틴을 사용할 수 있습니다. 
// 메시지 송신 시 과거의 메시지 송신 루틴에서 만들어진 버퍼 객체를 Proud.ByteArray 객체에 넣습니다. 
// 이후 Proud.ByteArray 객체를 RMI의 파라미터로 전송합니다.

// 메시지 객체 생성
Proud::CMessage msg;
 
/* 사용자가 직접 만든 msg 객체는 아직 어떤 버퍼를 써야 할지 지정되지 않았습니다.
이러한 경우 UseInternalBuffer를 호출해야만 << 연산자가 작동합니다.
UseInternalBuffer는 msg 객체에 아무것도 버퍼 사용이 지정되지 않음을 전제합니다.
따라서 이미 버퍼 사용이 지정된 경우 이 메서드를 호출해서는 안됩니다.
자세한 것은 Proud.CMessage.UseInternalBuffer 도움말을 참고하십시오. */
msg.UseInternalBuffer();
 
msg << a << b;
 
Proud::ByteArray block;
block.SetCount(msg.GetLength());
memcpy(block.GetData(), msg.GetData(), block.Count);
 
Foo(Proud::HostID_Server, Proud::RmiContext::ReliableSend, block);

// 메시지 수신 시 개발자가 구현하는 RMI 함수 내부에서 Proud.ByteArray객체를 RMI 파라미터로 받고, 
// 필요한 데이터를 추출합니다.

DEFRMI_MyPIDL_Foo(MyClass)
{
    // Parameter 'block' and the others are is given
    Proud::CMessage msg;
    msg.UseExternalBuffer(block.GetData(), block.Count);
    msg.SetLength(block.Count);
    msg >> a >> b;
    ...
}

모든 RMI 호출 시점을 접근하기

ProudNet에서는 RMI의 호출 시점을 접근할 수 있는 장치가 있습니다.

  • 호출되는 모든 RMI의 로그를 남기기

  • 각 RMI별로 실행되는 시간을 측정하여 게임 서버 성능 최적화

- 송신측(Proxy) 호출 시점 접근

1. 먼저, PIDL 컴파일러 결과물의 Proxy 파생 클래스를 만듭니다. 2. NotifySendByProxy 를 오버라이드 합니다

이렇게 하면 매 송신마다 오버라이드한 메서드가 호출됩니다.

기본적으로 NotifySendByProxy() 는 호출되도록 설정되어 있습니다만, 성능을 더 높이기 위해 NotifySendByProxy() 호출 자체를 막고 싶을 땐 m_enableNotifySendByProxyfalse로 설정해주면 NotifySendByProxy()의 호출이 더 이상 되지 않습니다.

- 수신측(Stub) 호출 시점 접근

1. Stub 인스턴스의 멤버 변수 m_enableStubProfiling(enableStubProfiling)true로 세팅합니다. 2. PIDL 컴파일러 결과물의 Stub 파생 클래스의 BeforeRmiInvocationAfterRmiInvocation를 오버라이드 합니다.

이렇게 하면 매 수신마다 오버라이드한 메서드가 호출됩니다.

도착한 RMI 실행 직전에 BeforeRmiInvocation 가 호출되고 실행이 끝나면 AfterRmiInvocation 가 호출됩니다. 이를 활용하면 긴 처리 시간으로 서버 성능에 문제를 일으키는 RMI를 찾는데 도움이 됩니다.

Stub에서 수신되는 RMI 함수의 파라미터를 모두 출력하는 방법 Stub 인스턴스의 멤버 변수 m_enableNotifyCallFromStub true로 세팅하고 NotifyCallFromStub 를 오버라이드합니다. 이 메서드는 파라미터를 문자열로 변환한 형태로 받으므로 여기에 로그를 남기면 됩니다. 다만, RMI 처리 성능이 떨어지니 반드시 필요할 때만 사용할 것을 권장합니다.

C#의 경우 따로 오버라이드 할 필요 없이 정의된 delegate 함수를 사용하면 됩니다.

변수도 마찬가지로 정의한 Stub 객체에서 찾을 수 있습니다.

RMI 이름 감추기

호스트가 주고받는 RMI의 이름을 BeforeRmiInvocation 등에서 나타나게 하기 위해 모든 RMI의 이름을 실행 파일에 보관할 수 있습니다.

하지만 보안 상 감추고 싶다면 아래와 같이 진행합니다.

PIDL의 컴파일 결과물 중 ..._proxy.cpp를 include 하기 전에 다음과 같이 정의합니다.

#define HIDE_RMI_NAME_STRING

1.7.36365 이후 버전부터 보안 상의 이유로 IRmiStub.BeforeRmiInvocation 함수에서는RMI 함수 이름이 기본적으로 나타나지 않습니다.

나타나게 하기 위해서는 PIDL 컴파일 결과물의 proxy, cpp 소스 파일이 컴파일 되기 전, 다음과 같이 정의합니다.

#define USE_RMI_NAME_STRING


⬅️ 뒤로

Last updated