[게임 서버] 6.6 원격 메서드 호출

게시:     수정

카테고리:

태그:

📦 6. 게임 네트워크 엔진 프라우드넷

👉🏻 6. 원격 메서드 호출

🔄 RMI란?

기존 방식 (6.4):

  • 이벤트 함수를 통해 바이너리 데이터를 주고받았다

RMI 방식:

  • RMI(원격 메소드 호출): 상대방 컴퓨터 내 프로그램의 특정 함수를 멀리서 실행
  • 프라우드넷의 RMI를 사용하면 더 편리하다

📤 송신 측 코드 (Proxy)

class SenderCode {
	// 자동 생성 코드
	Knight_Move(SendTo, position, motion) {
		Message msg;
		msg.Write(ID_Knight_Move);
		msg.Write(position);
		msg.Write(motion);
		Send(SendTo, msg);
	}
}

특징:

  • 함수 호출을 대신 해준다는 의미로 proxy라고 한다

📥 수신 측 코드 (Stub)

class ReceiveCode {
	ProcessReceivedMessage(Message msg) {
		ID = msg.Read();
		switch(ID) {
			case ID_Knight_Move:
				position = msg.Read();
				motion = msg.Read();
				Knight_Move(position, motion);
				break;
				...
		}
	}

	Knight_Move(position, motion) {
		// 코드 작성
	}

}

특징:

  • 수신하는 측에서는 메시지를 받고 함수를 호출해준다
  • 함수 호출해주는 기반이라는 의미로 stub이라고 한다

✨ 장점

  1. 송수신 처리 코드를 일일이 구현할 필요가 없다
  2. 송수신 메시지의 형태가 변경되어도, 송수신 코드를 수정하다 실수할 위험이 없다

🧮 계산기 구현 예시

1️⃣ RMI 함수 선언

PIDL 확장자 파일에서 선언:

global CalcC2S 1000 {
	RequestAdd([in] int a, [in] int b);
}

global CalcS2C 2000 {
	ResponseAdd([in] int sum);
}

구문 설명:

global <네임스페이스 이름> <메시지 ID>

네임스페이스 이름:

  • 송수신 코드는 Proxy와 Stub이라는 이름의 클래스로 만들어지며, 이들은 네임스페이스 안에 들어간다
  • 예: CalcS2C::Proxy

메시지 ID:

  • RMI 함수를 지칭하며, 정수 값이다
  • 1000, 2000은 RMI ID의 시작 값이며, 선언하는 각각의 RMI 함수는 1큰 수를 가진다
  • RMI ID를 수동 설정하는 방법은 나중에 설명한다

2️⃣ PIDL 파일 컴파일

// --- 클라이언트 ---
// 송신
CalcC2S::Proxy
// 수신
CalcS2C::Stub
CalcS2C::StubFunctional

// --- 서버 ---
// 송신
CalcS2C::Proxy
// 수신
CalcC2S::Stub
CalcS2C::StubFunctional
  • PIDL 파일을 컴파일했을 때, 컴파일러가 생성하는 클래스이다

3️⃣ 클래스 사용

Stub 사용:

// CalcC2S::Stub을 사용하는 경우
class MyStub : public CalcC2S::Stub {
	RequestAdd(from, rmiContext, a, b) {
		// 여기에 코드 입력
	}
}

myStub = new MyStub

StubFunctional 사용:

// CalcC2S::StubFunctional을 사용하는 경우
myStub = new CalcC2S:StubFunctional();

myStub.RequestAdd = [](from, rmiContext, a, b) {
	// 여기에 코드 입력
}
  • StubFunctional의 경우는 함수나 람다식을 넣으면 된다

4️⃣ 송신 코드(proxy)/수신 코드(stub) 부착

// 서버 측
CalcS2C::Proxy CalcS2CProxy;
s->AttachProxy(&CalcS2CProxy);
CalcC2S::StubFunctional CalcC2SStub;
s->AttachStub(&CalcC2SStub);

// 클라이언트 측
CalcC2S::Proxy CalcC2SProxy;
c->AttachProxy(&CalcC2SProxy);
CalcS2C::StubFunctional CalcS2CStub;
c->AttachStub(&CalcS2CStub);

서버:

  • CalcS2C.Proxy, CalcC2S.Stub 필요
  • NetServer에 부착

클라이언트:

  • CalcC2S.Proxy, CalcS2C.Stub 필요
  • NetClient에 부착

5️⃣ RMI 호출 및 호출 받기

// 서버 측
CalcS2CStub.RequestAdd_Function =
	[]PARAM_CalcC2SStub_RequestAdd // 1
	{
		int sum = a + b;
		// 2
		CalcS2CProxy.ResponseAdd(remote, RmiContext::ReliableSend, sum);
	};
};

// 클라이언트 측
// 3
CalcC2SProxy.RequestAdd(HostID_Server, RmiContext::ReliableSend, 3, 4);

// 4
CalcS2C.ResponseAdd_Function =
	[]PARAM_CalcS2CStub_ResponseAdd
	{
		print(sum);
	}
};

서버:

  • 1번: 클라이언트가 원격 호출한 RequestAdd() 함수를 람다식으로 넣어준다
    • PARAM_으로 시작하는 매크로는 람다식의 매개변수를 미리 정의해놓은 매크로다
    • 매크로는 송신자의 HostID, RmiContext를 처리한다
  • 2번: 처리 결과를 클라이언트의 원격 함수를 호출하여 전송한다
    • remote는 수신할 때 받았던 송신자의 식별자(HostID)이다

클라이언트:

  • 3번: 서버의 RequestAdd 함수를 원격 호출한다
    • 수신자의 HostID, RmiContext, 정의한 RMI 함수의 매개변수들을 넣어준다
  • 4번: 서버가 원격 호출한 ResponseAdd() 함수를 람다식으로 넣어준다
    • PARAM_으로 시작하는 매크로는 람다식의 매개변수를 미리 정의해놓은 매크로다
    • 매크로는 송신자의 HostID, RmiContext를 처리한다

🧐 정리

구성 요소 역할 위치
Proxy 원격 함수 호출 (송신) 호출하는 쪽
Stub 원격 함수 수신 및 실행 호출받는 쪽
PIDL RMI 함수 정의 컴파일 전

핵심 개념:

  • Proxy로 원격 함수 호출
  • Stub으로 원격 호출 수신
  • PIDL로 함수 선언, 자동 코드 생성
  • 타입 안전성과 편의성 확보

GameServer 카테고리 내 다른 글 보러가기

댓글남기기