언리얼에서의 커넥션 구성을 살펴봅니다.
1. 네트워크 통신을 담당하는 언리얼 주요 클래스
언리얼 엔진 통신의 구성은 하이레벨과 로우 레벨로 구성할 수 있습니다.
하이 레벨 : 게임 구성하는 단위인 액터, 컴포넌트, 월드와 같이 컨텐츠를 구성하는 오브젝트의 상태와 속성과 관련된 상위 개념을 의미한다.
로우 레벨 : 상태와 속성을 네트워크를 통해 전달(통신)하기 위해 만들어진 데이터 스트림을 말한다.
PlayerController 클래스 : 네트워크 통신에 접근 가능한 게임 내의 대표 액터 네트워크 커넥션을 관리합니다.
UNetConnection 클래스 : 상위에서 네트워크 통신을 담당하는 클래스. 패킷 데이터의 인코딩 디코딩, 네트워크 통신량 조절(대역폭 관리), 채널 관리를 합니다.
즉, 하이 레벨의 상태값이나 속성값을 로우 레벨로 원활하게 변경하여 전달할 수 있도록 준비하는 역할을 합니다.
인코딩과 디코딩은 데이터를 효율적으로 저장, 전송, 처리하도록 하는 중요한 역할을 수행한다.
인코딩은 데이터 압축, 다른 형식으로 변환하여 저장공간을 절약하고 전송 시간을 줄이는데 도움을 준다.
디코딩은 인코딩(압축 및 변형)된 데이터를 원래의 형태로 되돌려 사용자가 이해할 수 있게 만드는 역할을 한다.
UNetDriver 클래스 : 로우 레벨에서의 소켓 관리와 패킷 처리, 네트워크 통신 설정
2. 서버의 네트워크 초기화 과정
서버의 모드가 정해지는 부분은 현재 월드에 NetDriver 의 존재 유무를 기준으로 판단합니다.
서버는 월드의 Listen 함수를 호출해 NetDriver 를 생성하는데요, 이 NetDriver 가 서버 모드가 클라이언트-서버 인지, 스탠드얼론인지를 결정하는 것입니다.
위에서 얘기한 NetMode 의 존재 유무 파악과 서버 시작 과에 대해 코드를 보면서 살펴보겠습니다.
먼저, NetMode 가 어떻게 파악되는지 살펴볼 수 있는 함수로는 UWorld::InternalGetNetMode() 함수가 있습니다.
ENetMode UWorld::InternalGetNetMode() const
{
if (NetDriver != nullptr)
{
const bool bIsClientOnly = IsRunningClientOnly();
return bIsClientOnly ? NM_Client : NetDriver->GetNetMode();
}
(후략)
}
함수의 내용물을 보면, NetDriver 가 nullptr 가 아닌지를 먼저 체크합니다.
만약 NetDriver 가 nullptr 라면 스탠드얼론이라고 판단합니다. NetDriver 는 통신을 담당하여 커넥션을 관리하는 녀석이기 때문입니다.
NetDriver 가 nullptr 가 아니라면, 해당 함수 안에서 GetNetDriver() 함수를 통해 얻은 NetDriver 의 GetNetMode() 로 NetMode 의 상태를 가져와 네트워크 모드를 파악합니다.
NetMode 의 상태를 가져오는 함수인 GetNetMode() 의 내용물은 아래와 같습니다.
// Normal
return (IsServer() ? (GIsClient ? NM_ListenServer : NM_DedicatedServer) : NM_Client);
이 때 NetMode 를 판단하는 IsServer() 함수는 어떤 함수일까요?
언리얼 엔진에서는 이 특징을 활용해서 현재 어플리케이션이 서버 모드인지 클라이언트 모드인지를 확인할 수 있도록 하는 함수인 IsServer() 라는 함수가 존재합니다..
NetDriver 는 다수의 커넥션을 관리하며, 서버와 클라이언트에 따라 다르게 동작합니다.
클라이언트에서의 NetDriver 는 항상 하나의 ServerConnection 만을 가지고, 서버에서의 NetDriver 는 다수의 ClientConnection 을 가집니다.
클라이언트의 NetDriver 는 초기화될 때 항상 ServerConnection을 가지고 있습니다. 만약 ServerConnection 이 Null 이면(없으면) 서버라는 뜻이겠죠.
bool UNetDriver::IsServer() const
{
// Client connections ALWAYS set the server connection object in InitConnect()
// @todo ONLINE improve this with a bool
return ServerConnection == NULL;
}
서버가 어떻게 시작되는지는 UWorld::Listen() 함수로 확인할 수 있습니다.
bool UWorld::Listen( FURL& InURL )
Listen 함수에서 하는 역할은 NetDriver 를 만들어주는 것입니다.
// Create net driver.
if (GEngine->CreateNamedNetDriver(this, NAME_GameNetDriver, NAME_GameNetDriver))
{
NetDriver = GEngine->FindNamedNetDriver(this, NAME_GameNetDriver);
#if UE_WITH_IRIS
if (IrisSystemHolder.IsHolding())
{
NetDriver->RestoreIrisSystem(IrisSystemHolder.ReplicationSystem);
IrisSystemHolder.Clear();
}
#endif // UE_WITH_IRIS
NetDriver->SetWorld(this);
FLevelCollection* const SourceCollection = FindCollectionByType(ELevelCollectionType::DynamicSourceLevels);
if (SourceCollection)
{
SourceCollection->SetNetDriver(NetDriver);
}
FLevelCollection* const StaticCollection = FindCollectionByType(ELevelCollectionType::StaticLevels);
if (StaticCollection)
{
StaticCollection->SetNetDriver(NetDriver);
}
}
Listen 함수에서 NetDriver 가 생성되기 전에는 InternalGetNetMode() 함수에서 NetDriver 가 nullptr 이기 때문에 NetMode 를 스탠드얼론 상태로 판단합니다. 하지만 Listen 함수가 호출되어 NetDriver 가 생성된 이후에는 제대로 된 NetMode 가 다시 판단되어집니다.
'게임개발 > ue server' 카테고리의 다른 글
[UE] 네트워크 모드에서의 액터의 준비와 게임 시작 (1) | 2024.06.16 |
---|---|
[UE] 게임 모드와 플레이어 컨트롤러를 활용한 로그인 플로우의 이해 (0) | 2024.05.08 |
[UE] 어플리케이션의 네트워크 모드 파악하기 (0) | 2024.04.29 |
[UE] 언리얼 엔진의 멀티플레이어 게임 프레임워크 특징과 네트워크 프로그래밍에서 BP가 아닌 C++을 사용해야 하는 이유 (0) | 2024.04.28 |
[UE5] 언리얼 멀티플레이어 네트워킹 (0) | 2024.04.28 |