TIL: Unreal Engine Server RPC 검증과 Reliable RPC 이해하기
오늘 배운 내용
오늘은 Unreal Engine 멀티플레이에서 Server RPC에 사용하는 WithValidation, _Implementation(), _Validate(), Reliable RPC의 의미를 정리했다.
핵심은 RPC가 단순히 함수를 호출하는 것이 아니라, 네트워크를 통해 서버와 클라이언트 사이에서 실행 위치와 검증 과정을 구분한다는 점이었다.
특히 Server RPC는 클라이언트가 서버에게 요청을 보내는 구조이기 때문에, 서버 입장에서는 이 요청이 정상적인지 확인할 필요가 있다.
클라이언트는 사용자가 조작할 수 있는 영역이기 때문에 서버는 클라이언트가 보낸 값을 그대로 믿으면 안 된다.
그래서 Server RPC에서는 요청을 검증하는 과정과 실제 실행하는 과정을 구분해서 이해해야 한다.
1. Server RPC에서 WithValidation을 사용하는 이유
WithValidation은 Server RPC에서 클라이언트의 요청을 서버가 실행하기 전에 검사하기 위해 사용한다.
클라이언트가 서버에게 어떤 요청을 보낼 때, 그 요청이 항상 정상적인 값이라고 보장할 수는 없다.
예를 들어 클라이언트가 비정상적인 값이나 조작된 요청을 서버로 보낼 수도 있다.
그래서 Server RPC에 WithValidation을 붙이면 서버가 RPC 실행 전에 해당 요청이 정상적인지 검증할 수 있다.
UFUNCTION(Server, Reliable, WithValidation)
void ServerRPCPrintChatMessageString(
const FString& InChatMessageString
);
이렇게 선언하면 서버 RPC는 검증 함수와 실제 실행 함수로 나뉘어 처리된다.
클라이언트가 Server RPC 호출
↓
서버에서 _Validate() 실행
↓
검증 결과가 true이면 통과
↓
_Implementation() 실행
정리하면 WithValidation은 RPC 실행 여부를 검증하고 위변조를 방지하기 위한 장치라고 볼 수 있다.
2. WithValidation이 붙은 RPC는 두 함수로 나뉜다
WithValidation이 붙은 Server RPC는 구현부에서 두 개의 함수로 나뉜다.
_Validate()
_Implementation()
예를 들어 다음과 같은 Server RPC가 있다고 하면,
UFUNCTION(Server, Reliable, WithValidation)
void ServerRPCPrintChatMessageString(
const FString& InChatMessageString
);
CPP에서는 다음 두 함수를 작성해야 한다.
bool ACXPlayerController::
ServerRPCPrintChatMessageString_Validate(
const FString& InChatMessageString)
{
return true;
}
void ACXPlayerController::
ServerRPCPrintChatMessageString_Implementation(
const FString& InChatMessageString)
{
// 실제 서버에서 실행될 코드
}
여기서 _Validate()는 실행 가능 여부를 검사하는 함수이고, _Implementation()은 검사를 통과한 뒤 실제로 실행되는 함수다.
3. _Validate()의 의미
_Validate()는 클라이언트가 보낸 RPC 요청이 정상적인지 서버에서 검사하는 함수다.
반환 타입은 bool이다.
bool ACXPlayerController::
ServerRPCPrintChatMessageString_Validate(
const FString& InChatMessageString)
{
return true;
}
return true;를 하면 서버가 이 요청을 정상 요청으로 판단하고 _Implementation()을 실행한다.
반대로 return false;를 하면 서버는 이 요청을 비정상 요청으로 판단하고 실행하지 않는다.
return true
-> 정상 요청
-> _Implementation() 실행
return false
-> 비정상 요청
-> _Implementation() 실행 안 함
예를 들어 채팅 메시지가 너무 길면 거부하고 싶을 때는 다음처럼 작성할 수 있다.
bool ACXPlayerController::
ServerRPCPrintChatMessageString_Validate(
const FString& InChatMessageString)
{
return InChatMessageString.Len() <= 100;
}
이 코드는 메시지 길이가 100자 이하일 때만 서버 RPC 실행을 허용한다.
즉, _Validate()는 서버 RPC의 검문소 같은 역할을 한다.
4. _Implementation()의 의미
_Implementation()은 검증을 통과한 RPC가 실제로 실행되는 함수다.
Server RPC라면 이 함수는 서버에서 실행된다.
void ACXPlayerController::
ServerRPCPrintChatMessageString_Implementation(
const FString& InChatMessageString)
{
// 서버에서 실제로 실행할 코드
}
예를 들어 클라이언트가 채팅 메시지를 서버로 보내면, 서버는 _Implementation() 안에서 그 메시지를 처리할 수 있다.
void ACXPlayerController::
ServerRPCPrintChatMessageString_Implementation(
const FString& InChatMessageString)
{
for (TActorIterator<ACXPlayerController> It(GetWorld());
It;
++It)
{
ACXPlayerController* CXPlayerController = *It;
if (IsValid(CXPlayerController))
{
CXPlayerController
->ClientRPCPrintChatMessageString(
InChatMessageString
);
}
}
}
이 코드는 서버가 모든 PlayerController를 순회하면서 각 클라이언트에게 메시지를 보내는 구조다.
정리하면 _Implementation()은 RPC의 실제 실행부다.
5. _Validate()와 _Implementation()의 차이
두 함수의 차이는 다음과 같다.
_Validate()
- RPC 요청을 실행해도 되는지 검사
- bool 값을 반환함
- true이면 실행 허용
- false이면 실행 거부
_Implementation()
- 검증을 통과한 뒤 실제로 실행되는 함수
- RPC의 본문 역할
- 실제 서버 로직을 작성하는 곳
흐름으로 보면 다음과 같다.
클라이언트가 Server RPC 호출
↓
서버에서 _Validate() 실행
↓
true 반환
↓
서버에서 _Implementation() 실행
쉽게 말하면 _Validate()는 입장 검사이고, _Implementation()은 실제 작업이다.
6. Reliable RPC의 의미
Reliable RPC는 원격 PC에서 반드시 실행되어야 하는 중요한 로직에 사용한다.
예를 들어 채팅 메시지, 아이템 사용, 게임 결과 처리처럼 누락되면 안 되는 요청은 Reliable로 보내는 것이 적절하다.
UFUNCTION(Server, Reliable)
void ServerRPCSendChatMessage(
const FString& Message
);
Reliable은 네트워크 상황이 좋지 않아도 해당 RPC가 전달되도록 보장하려는 방식이다.
반대로 한두 번 누락되어도 큰 문제가 없는 이펙트, 사운드, 짧은 애니메이션 효과 같은 것은 Unreliable을 사용할 수 있다.
Reliable
- 중요한 RPC
- 반드시 전달되어야 하는 요청
- 채팅, 아이템 사용, 게임 결과 처리 등에 사용
Unreliable
- 조금 누락되어도 괜찮은 RPC
- 이펙트, 사운드, 빈번한 위치 갱신 등에 사용
따라서 Reliable RPC는 원격 PC에서 반드시 실행되어야 하는 로직에 사용하는 것이 맞다.
7. Reliable을 무조건 많이 쓰면 안 되는 이유
Reliable은 반드시 전달되어야 하는 RPC에 사용하지만, 모든 RPC를 Reliable로 만드는 것은 좋지 않다.
Reliable RPC가 너무 많이 쌓이면 네트워크 큐에 부담이 생길 수 있다.
중요하지 않은 이펙트나 반복적인 상태 갱신까지 모두 Reliable로 보내면 오히려 네트워크 성능에 문제가 생길 수 있다.
따라서 Reliable과 Unreliable은 로직의 중요도에 따라 구분해서 사용해야 한다.
반드시 실행되어야 한다
-> Reliable
조금 빠져도 괜찮다
-> Unreliable
채팅처럼 사용자가 입력한 메시지는 누락되면 안 되므로 Reliable이 적절하다.
하지만 총알 이펙트나 발자국 소리처럼 순간적으로 지나가는 효과는 Unreliable도 사용할 수 있다.
오늘 헷갈렸던 점
오늘 가장 헷갈렸던 부분은 _Implementation()과 _Validate()의 역할이었다.
처음에는 둘 다 RPC 실행과 관련된 함수라서 차이가 명확하지 않았다.
하지만 정리해보면 _Validate()는 실행 전에 요청을 검사하는 함수이고, _Implementation()은 검증을 통과한 뒤 실제로 실행되는 함수다.
또 Reliable RPC는 무조건 좋은 것이 아니라, 반드시 실행되어야 하는 중요한 로직에만 사용하는 것이 적절하다는 점도 중요했다.
Server RPC는 클라이언트가 서버에게 요청을 보내는 구조이기 때문에, 서버는 클라이언트의 요청을 그대로 신뢰하지 않고 검증할 수 있어야 한다.
오늘의 핵심 정리
- WithValidation은 Server RPC 요청을 서버에서 검증하기 위해 사용한다.
- Server RPC는 클라이언트가 서버에게 요청을 보내는 구조다.
- 서버는 클라이언트 요청을 무조건 믿으면 안 된다.
- WithValidation이 붙은 RPC는 _Validate()와 _Implementation()으로 나뉜다.
- _Validate()는 RPC 요청을 실행해도 되는지 검사한다.
- _Validate()가 true를 반환하면 _Implementation()이 실행된다.
- _Validate()가 false를 반환하면 RPC 실행이 거부된다.
- _Implementation()은 RPC의 실제 실행부다.
- Reliable RPC는 원격 PC에서 반드시 실행되어야 하는 로직에 사용한다.
- 모든 RPC를 Reliable로 만들면 네트워크에 부담이 될 수 있다.
- 누락되면 안 되는 요청은 Reliable을 사용한다.
- 조금 누락되어도 괜찮은 이펙트나 사운드는 Unreliable을 사용할 수 있다.
정리하면 Server RPC에서는 요청을 검증하는 단계와 실제 실행하는 단계를 구분해야 한다.
그리고 네트워크 RPC는 중요도에 따라 Reliable과 Unreliable을 구분해서 사용해야 한다.
'unreal 8기' 카테고리의 다른 글
| 2026-6-17 TIL (0) | 2026.06.17 |
|---|---|
| 2026-6-16 TIL (0) | 2026.06.16 |
| 2026-6-11 TIL (0) | 2026.06.11 |
| 2026-6-10 TIL (0) | 2026.06.10 |
| 2026-6-9 TIL (0) | 2026.06.09 |