4 분 소요

RPC(Remote Procedure Call)

Image

언리얼의 네트워크 환경에서
서버 / 클라이언트가 함수를 호출하며
‘다른 쪽’에서 실행되게 하는 기능

  • 클라 -> 서버
  • 서버 -> 단일 클라
  • 서버 -> 모든 클라

‘호출하는 PC’와 ‘실행’하는 PC가 달라도 되는 통신 기법

RPC의 주요 용도

  • 전반적으로 ‘게임’에 큰 영향을 끼치지 않는 일시적 효과에 적용
    • 주로 코스메틱(Sound, Particle 등)에 사용
    • 그 외에도 애니메이션 트리거, UI 알림 등에 고려 가능
      (시청각적 연출)
      (서버 -> 클라)
    • 반대로 클라 -> 서버의 경우 ‘이동’을 제외한
      입력 정보를 RPC로 보내는 방식
      • 이동의 경우는 CharacterMovement 컴포넌트가 내부적으로
        네트워크 경로로 전송한다고 함
      • ‘이동’은 너무 빈번히 일어나기에 RPC를 일일이 호출하기엔 너무 무겁기 때문
  • 한 순간의 ‘함수 호출’에 의미를 둠
    • 지속 상태 보장 x
    • 전달 실패 시, 재전달을 고려하지 않음
    • 신규 유저 접속 시 RPC가 과거의 호출 결과를 동기화 하지 않음
  • 따라서 ‘게임’에 전반적인 영향을 미치는 ‘상태’를 적용하려면
    Property Replication 등을 고려할 것

RPC 동작의 전제 조건

  • Actor 본인은 네트워크에 복제되어 있어야 함
    • bReplicates = true;
    • SetReplicateMovement(true); : 캐릭터의 ‘이동’이 복제되기 위한 전제조건
    • Component라면 부착된 Actor가 Replication 대상이어야 함
  • RPC 함수는 다음과 같은 조건이 필요
    • UFUNCTION() + Net 관련 지정자
    • 호출 주체(Actor / Component)의 NetRole이 적절해야 함
    • 호출 Actor의 OwnerShip이 중요
      • 클라라면 자신이 Owner인 Actor에서만 Server RPC 호출 가능
// 클라에서 호출되고, 서버에서 실행
// Reliable - 원격에서 무조건 실행 하도록 설정
UFUNCTION(Server, Reliable)
void ServerFire();

// 서버에서 호출되고 클라에서 실행
// Unreliable - 디폴트값, 실행 보장은 안함 (놓치더라도 큰 영향이 없는 경우)
UFUNCTION(Client, Unreliable)
void ClientPlayEffect();
  • NetRole
    • UE5에선 Role / NetRole 필드 자체는 제거 되었지만
      여전히 관련 메서드가 존재
    • 따라서 호출 주체의 NetRole을 다시 체크할 것

Call

코드에서 RPC 함수 호출 시도됨

  • 특정 클라/서버 에서 ‘어떠한 Actor’가 RPC를 호출(Call)

ex)

Client  Actor.ServerDoSomething()

이러면 클라이언트에서 RPC를 Call 한것이다

  • 보통 컴파일 타임에 ‘호출’과 ‘실행’할 곳이 정해짐
  • ‘직접’ 함수를 ‘호출’하고 실행

Invoke

규칙을 따라 실제 RPC가 네트워크를 통해 전달되어 실행

  • 런타임에 호출/실행 할 곳이 정해지는 경우를 뜻함
    • 함수 포인터
    • 동적 바인딩(Delegate)
  • RPC가 호출되어도(Call)
    권한 / OwnerShip 등으로 실행이 거부되는 등의 사태가 발생 가능
    (이 경우, Call 되었으나 Invoke 되지는 않음)

  • RPC 호출 위치와 Actor의 OwnerShip에 따라
    실제 RPC가 실행되는 위치를 정의한 표

RPC 호출에 대한 정리 표

Image

요점만 짚자면

  • RPC를 호출한 주체
  • Actor의 OwnerShip
  • RPC 타입

의 3요소에 따라서 실제 RPC가 어느 쪽에서
Invoke 되는지가 달라짐
(위는 이를 정리한 표)

  • Not Replicated?
    RPC가 아니라 ‘일반 함수’(복제 되지 않은)를 호출한 경우에 대한 이야기
    서버에서 ‘일반 함수’ 호출 시 - 서버에서만 작동
    클라에서 ‘일반 함수’ 호출 시 - 로컬에서만 작동

RPC 호출 타입

  • NetMulticast
    서버를 포함한 모든 클라에서 해당 RPC 실행

Image

  • Server
    서버에서 해당 RPC를 실행

Image

  • Client
    클라이언트에서 해당 RPC를 실행

Image

주체가 서버인 RPC 호출

기본적으로 ‘권한’이 가장 크기에 비교적 규칙이 단순한 편

Actor Ownership NetMulticast Server RPC Client RPC
Client-owned actor 서버 + 모든 클라 서버 Actor의 Owner 클라이언트에서만
Server-owned actor 서버 + 모든 클라 서버 서버에서만 (클라에 안 감)
Unowned actor 서버 + 모든 클라 서버 서버에서만

Actor OwnerShip

  • Client-Owned : 플레이어의 Pawn / Controller 등
  • Server-Owned : NPC나 GameMode 등
  • Unowned : 문, 아이템 등

RPC Type 별 결과

  • NetMulticast
    서버에서 해당 타입의 RPC 호출 시
    서버 + 모든 클라에 전파
  • Server RPC
    자기 자신의 RPC이기에 서버에서 실행
  • Client RPC
    • Actor에 Owner가 있다면 해당 Client에서만
    • 아니라면 서버에서만 실행

주체가 클라이언트인 RPC 호출

조건에 따라 Drop 되는 경우가 있기에 주의가 필요한 편

Actor Ownership NetMulticast Server RPC Client RPC
Owned by invoking client 로컬에서만 실행 서버에서 실행됨 로컬에서만 실행
Owned by a different client 로컬에서만 실행 Drop됨 로컬에서만 실행
Server-owned actor 로컬에서만 실행 Drop됨 로컬에서만 실행
Unowned actor 로컬에서만 실행 Drop됨 로컬에서만 실행

Actor OwnerShip

  • Owned by invoking client
    PlayerController가 Local PlayerController와 같은 경우 (내 캐릭터)
  • Owned by a different client
    PlayerController가 Local PlayerController와 다른 경우 (친구 캐릭터)
  • Server-owned
    서버에서 Spawn된 Actor (NPC, 서버용 게임 객체)
  • Unowned
    클라이언트가 소유하지 않은,
    보통 월드에 배치된 상호작용용 객체(문,상자 등)

RPC Type 별 결과

  • NetMulticast
    클라에서 호출시 언제나 로컬 실행
    (따라서 해당 RPC 호출은 서버에게 일임할 것)
  • Server RPC
    클라이언트가 Owned인 Actor 에서만 서버 Invoke됨
    (그 외의 경우는 Drop)
    (보안상의 이유)
  • Client RPC
    클라 호출 시, 항상 로컬에서만 실행됨

자주 쓰이는 여러 케이스 들

  • RPC가 클라에서 호출되고, 서버에서 실행되어야 한다면?
    Server 키워드를 사용하기
    • ClientConnection 이 소유하고 있는 액터(Client-Owned)에서 RPC가 호출
    • _Validate() 함수에서 RPC를 실행할지 말지 결정

Image

  • RPC가 서버와 모든 클라에서 실행되어야 한다면?
    NetMulticast 키워드를 사용하기
    • 서버에서 호출해야 함
    • 부하가 심하므로, 너무 빈번히 호출하는건 권장 x
      (ex : Tick())

Image

  • RPC가 서버에서 호출되고, 클라에서 실행되어야 한다면?
    Client 키워드를 사용하기
    • 서버에서 호출해야 함

Image

WithValidation

UFUNCTION() 매크로와 함께 사용되는 키워드

  • 서버 RPC 사용 권장
  • _Implementation()_Validate()를 통해
    클라이언트가 보낸 RPC가 유효한지를 ‘서버에서 검증’
  • _Validate() 함수는 해당 RPC가 서버에서 실제 실행할지 말지 결정
  • 서버 실행 로직이 ‘무조건’적으로 신뢰되기에 위변조를 막기 위한 방어막 역할
UFUNCTION(Server, Reliable, WithValidation)
void MyFunction(int32 MyInt);

// 1) 서버에서 실제 로직
void MyClass::MyFunction_Implementation(int32 MyInt)
{
    // 진짜 실행 로직
}

// 2) 서버에서 먼저 호출되는 검증용 함수
bool MyClass::MyFunction_Validate(int32 MyInt)
{
    // 파라미터 / 상태 검증
    // 유효하면 true, 이상하면 false
    return MyInt >= 0 && MyInt <= 100;
}
  1. 클라이언트에서 MyFunction(Server RPC) 호출
  2. 서버에서 _Validate() 를 먼저 실행
  3. 결과가 true 인 경우에 _Implementation() 호출
  • _Implementation()에서 체크하는 방식도 존재
    (이 방식으로 유효성을 검사하는 방식도 있다)

댓글남기기