RPC (Remote Procedure Call) 는 로컬에서 호출되지만 (호출하는 머신과는) 다른 머신에서 원격 실행되는 함수를 말합니다.

RPC 함수는 매우 유용하게 사용될 수 있으며, 네트워크 연결을 통해 클라이언트와 서버 사이에 메시지를 전송할 수 있습니다.

이 기능의 주요 용도는 속성상 장식이나 휘발성인 비신뢰성 게임플레이 이벤트를 위한 것입니다. 이는 사운드 재생, 파티클 스폰, 액터의 핵심적인 기능과는 무관한 일시적 효과와 같은 작업을 하는 이벤트를 포함합니다. 기존에 이러한 유형의 이벤트는 종종 액터 프로퍼티를 통해 리플리케이트되고는 했습니다.

RPC 사용시 오너십 작동 방식 을 이해해 두는 것이 중요합니다. 대부분의 RPC 실행 장소를 결정하기 때문입니다.

RPC 사용하기

함수를 RPC 로 선언하려면 UFUNCTION 선언에 Server, Client, NetMulticast 키워드를 붙여주기만 하면 됩니다.

예를 들어 함수를 서버에서 호출되지만 클라이언트에서 실행되는 RPC 로 선언하려면, 이렇게 합니다:

UFUNCTION( Client )
void ClientRPCFunction();

함수를 클라이언트에서 호출되지만 서버에서 실행되는 RPC 로 선언하는 것은 Server 키워드를 사용한다는 것 빼고는 매우 비슷합니다:

UFUNCTION( Server )
void ServerRPCFunction();

Multicast 라 불리는 특수 유형 RPC 함수가 하나 더 있습니다. Multicast RPC 는 서버에서 호출된 다음 서버는 물론 현재 연결된 모든 클라이언트에서도 실행되도록 고안된 것입니다. 멀티캐스트 함수를 선언하려면 그냥 NetMulticast 키워드를 사용하면 됩니다:

UFUNCTION( NetMulticast )
void MulticastRPCFunction();

멀티캐스트 RPC 는 클라이언트에서도 호출 가능하지만, 이 경우 로컬에서만 실행됩니다.

간단 팁

함수 초반에 Client, Server, Multicast 키워드를 앞쪽에 어떻게 붙였는지 보세요. 저희 내부적으로 합의한 규칙으로, 이 함수를 사용하는 프로그래머들에게 이 함수가 각각 클라이언트, 서버, 모든 클라이언트에서 호출된다는 것을 알리기 위한 것입니다.

멀티플레이어 세션 도중 이 함수가 어느 머신에서 호출되는지 한 눈에 알아볼 수 있기에 매우 유용합니다.

요건 및 주의사항

RPC 의 정상 작동을 위해 충족시켜야 하는 요건이 몇 가지 있습니다:

  1. Actor 에서 호출되어야 합니다.
  2. Actor 는 빈드시 replicated 여야 합니다.
  3. 서버에서 호출되고 클라이언트에서 실행되는 RPC 의 경우, 해당 Actor 를 실제 소유하고 있는 클라이언트에서만 함수가 실행됩니다. (client)
  4. 클라이언트에서 호출되고 서버에서 실행되는 RPC 의 경우, 클라이언트는 RPC 가 호출되는 Actor 를 소유해야 합니다.
  5. Multicast RPC 는 예외입니다:
    • 서버에서 호출되는 경우, 서버에서는 로컬에서 실행될 뿐만 아니라 현재 연결된 모든 클라이언트에서도 실행됩니다.
    • 클라이언트에서 호출되는 경우, 로컬에서만 실행되며, 서버에서는 실행되지 않습니다.
    • 현재 멀티캐스트 이벤트에 대해 단순한 스로틀 조절 메카니즘이 있습니다. 멀티캐스트 함수는 주어진 액터의 네트워크 업데이트 기간동안 두 번 이상 리플리케이트되지 않습니다. 장기적으로 크로스 채널 트래픽 관리 및 스로틀 조절 지원을 개선시킬 계획입니다.

 

Autority

Role_Autority : 서버상에 존재하는 복제된 액터, 서버만이 액터의 변수와 상태에 대한 권한을 갖고 있음,
Role_AutonomousProxy : 소유한 클라이언트에 존재하는 액터의 버전으로 간주함, 클라와 서버간의 직접적인 RPC 송수신 등의 작업을 수행함
Role_SimulatedProsy : 다른 모든 클라이언트에 있는 액터 버전으로 간주한다, 순전히 시뮬레이터이며 액터 상태에 대한 아무런 권한이 없음(조정할수 없는 다른 캐릭터들)의 역할

 

(멀티 플레이 접속시) 서버에선 플레이어 컨트롤러 2개(플레이어 수만큼), 클라이언트에선 플레이어 컨트롤러가 1개이다

 

아래는 리슨 서버로 실행하여 서버 pc 에서 본 화면

 

  • 플레이어 컨트롤러는 소유 클라이언트에서 생성되며 플레이어 컨트롤러는 서버와의 모든 통신이 이뤄지는 채널이다
    (이것이 비 소유 클라이언트와의 차이임)
  • (멀티 플레이 접속시) 서버에선 플레이어 컨트롤러 2개(플레이어 수만큼)
    클라이언트에선 플레이어 컨트롤러가 1개이다

    각 컨트롤러는 서버와 소유 클라이언트 간에 복제된다, 같은 맥락으로 게임 모드는 네트워크 권한에서만 생성된다(이경우는 대게 서버임),  클라이언트와 서버 간의 게임 플레이어 정보를 전달하는 방법은 GameState 와 PlayerState 오브젝트를 통해 이뤄지는데 이 두 오브젝트도 연결된 모든 클라이언트에 복제된다

 

 

서버와 클라이언트 통신 할때 GameState 와 PlayerState 오브젝트를 통해서 정보 전달이 이뤄진다

그리고 이 두 오브젝트는 연결된 모든 클라이언트에 복제된다

 

Player state : 플레이어 상태 : 모든 플레이어는 서버(혹은 스탠드 얼론 게임)에 각자의 PlayerState를 가집니다. 

PlayerState는 모든 클라이언트에게 리플리케이트 되며

플레이어의 네트워크와 관련 정보를 지니게 된다, 플레이어 이름, 점수 등등

 

 

다음 표는 호출 액터의 소유권(가장 왼쪽 열)에 따라 주어진 유형의 RPC 실행 위치를 나타냅니다.

서버에서 호출된 RPC

액터 소유권리플리케이트 안됨NetMulticast서버클라이언트

 

RPC 는 호출 PC 에서 액터의 소유권을 보고 호출되는 대상이 1차적으로 정해지고, 그다음 프래그를 보고 어떻게 호출할지 2차적으로 결정 된다

 

Multicast 는 소유권과 관계 없이 동작하는 특성을 갖음

리플리케이트 안됨 = 리플리케이트 없는 상태일때를 말함

서버소유 액터 일때 NetMulticast 도 서버와 모든 클라이언트에서 실행이다

 

 

 

 

클라이언트에서 호출된 RPC

액터 소유권리플리케이트 안됨NetMulticast서버클라이언트

 

 


위 표를 기준으로 Multicast 예를 들자면

[호출 PC 가 서버에서 호출인 경우 ]

Multicast RPC 는 서버에서 호출되는 경우서버와 현재 연결된 모든 클라이언트에서 실행된다

 

[호출 PC 가 클라이언트에서 호출하는 경우 ]

클라이언트에서 호출되는 경우 소유권에 관계 없이 로컬에서만 실행되며 서버에서 실행되지 않는다

 

 

 

신뢰성

기본적으로 RPC 는 비신뢰성입니다. RPC 호출이 원격 머신에서 확실히 실행되도록 하기 위해서는 Reliable 키워드를 붙이면 됩니다:

UFUNCTION( Client, Reliable )
void ClientRPCFunction();

블루프린트

RPC 로 마킹된 함수는 블루프린트에서 호출해도 리플리케이트됩니다. 이 경우 마치 C++ 에서 호출된 것과 같은 규칙을 따릅니다. 현재 블루프린트에서 동적으로 함수를 RPC 마킹하는 것은 가능하지 않습니다.

하지만 Custom event 는 블루프린트 에디터 안에서 replicated 마킹 가능합니다.

이 기능을 사용하기 위해서는, 이벤트 그래프에서 custom event 를 새로 만듭니다. custom event 에 클릭한 다음 디테일 뷰에서 Replication 세팅을 편집합니다:

인증

최근, 악성 데이터/입력 감지를 위한 관문 역할을 위해 RPC 에 인증(validation) 함수를 추가하는 기능이 생겼습니다. RPC 에 대한 인증 함수가 악성 파라미터를 감지한 경우, 해당 RPC 를 호출한 클라이언트/서버 연결을 끊도록 시스템에 알린다는 개념입니다.

RPC 에 대해 인증 함수를 선언하려면, UFUNCTION 선언문에 WithValidation 키워드를 추가해 주기만 하면 됩니다:

UFUNCTION( Server, WithValidation )
void SomeRPCFunction( int32 AddHealth );

그런 다음 Implementation 함수 옆 어딘가에 Validate 함수를 넣어주면 됩니다.

bool SomeRPCFunction_Validate( int32 AddHealth )
{
    if ( AddHealth > MAX_ADD_HEALTH )
    {
        return false;                       // This will disconnect the caller
    }
    return true;                              // This will allow the RPC to be called
}

void SomeRPCFunction_Implementation( int32 AddHealth )
{
    Health += AddHealth;
}

좀 더 최근에, 클라이언트->서버 RPC 의 경우 _Validation 함수를 포함하도록 UHT 를 변경했습니다. 서버 RPC 함수의 안전성 확보를 위해, 알려진 모든 입력 제한에 대해 각각의 모든 파라미터의 유효성 검사를 위한 코드를 쉽게 추가할 수 있도록 하기 위한 것입니다.

 

 

ref : https://docs.unrealengine.com/4.27/ko/InteractiveExperiences/Networking/Actors/RPCs/

반응형

+ Recent posts