NetMode
- 해당 게임 프로세스가 네트워크 상에서 어떤 역할을 하고 있는지를 의미.
- 싱글(NM_StandAlone), 서버(NM_Listen, NM_DedicatedServer), 클라이언트(NM_Client)
게임에 중대한 영향을 미치는 로직은 서버 컴퓨터에서 처리하는데 이유는 해킹에 취약해지기 때문이다.
NetMode는 작성하고 있는 로직이 서버에서 돌고 있는지 클라이언트에서 돌고 있는지 알아야 할 때 필요하다.
UWorld::InternalGetNetMode() 함수는 언리얼에서 구현해놓은 함수인데 코드를 살펴보면
// World.cpp
...
ENetMode UWorld::InternalGetNetMode() const
{
if ( NetDriver != NULL ) // 넷드라이버가 설정되어 있으면
{
const bool bIsClientOnly = IsRunningClientOnly();
return bIsClientOnly ? NM_Client : NetDriver->GetNetMode(); // 클라 아니면 서버 둘 중 하나다.
}
...
}
// NetDriver.cpp
ENetMode UNetDriver::GetNetMode() const
{
#if WITH_EDITOR
if (World && World->WorldType == EWorldType::PIE && IsServer())
{
FWorldContext* WorldContext = GEngine->GetWorldContextFromWorld(World);
if (WorldContext && WorldContext->RunAsDedicated) // 데디로 실행했다면
{
return NM_DedicatedServer; // 데디 서버 반환.
}
}
#endif
return (IsServer() ? (GIsClient ? NM_ListenServer : NM_DedicatedServer) : NM_Client);
// 서버인데, 클라이언트로 참여하고 있다? 리슨서버. 서버인데 참여하고 있지 않다? 데디서버.
}
// NetDriver.cpp
bool UNetDriver::IsServer() const
{
// Client connections ALWAYS set the server connection object in InitConnect()
// @todo ONLINE improve this with a bool
return ServerConnection == NULL;
// 클라이언트는 무조건 서버 커넥션을 가지고 있다.
}
| 특징 | |
| StandAlone |
|
| Client |
|
| Listen Server |
|
| Dedicated Server |
|
NetConnection
넷 커넥션은 다른 PC와 연결이 발생하면 그에 대응하는 넷 커넥션 객체가 생성이 된다.
서버에 클라이언트가 접속하면 서버에는 클라이언트 커넥션, 클라이언트에는 서버 커넥션 객체가 생성이 된다.
두 PC(서버와 클라이언트)는 넷 커넥션 객체를 통해 통신을 하게 된다.
NetDriver는 생성된 넷 커넥션 객체를 소유하고 관리를 한다.
서버 PC에 생성된 넷 드라이버는 접속한 클라이언트의 수 만큼 넷 커넥션을 관리한다.
(서버에서는 1개의 넷 드라이버가 접속한 클라이언트의 수 만큼 넷 커넥션을 관리한다.)
클라이언트 PC에 생성된 넷 드라이버는 서버 커넥션 하나만 관리를 한다.
(클라이언트에는 하나의 서버만 연결이 되므로 넷 드라이버도 서버 커넥션 하나만 관리를 한다.)
이는 서버 - 클라이언트 구조의 특징이다.
// NetDriver.h
...
UCLASS(...)
class UNetDriver : public UObject, public FExec
{
...
/** Connection to the server (this net driver is a client) */
UPROPERTY()
TObjectPtr<class UNetConnection> ServerConnection;
/** Array of connections to clients (this net driver is a host) - unsorted, and ordering changes depending on actor replication */
UPROPERTY()
TArray<TObjectPtr<UNetConnection>> ClientConnections;
...
위 코드는 언리얼에서 작성해놓은 코드인데 보면 알 수 있듯이 넷 드라이버가 서버 커넥션은 1개의 객체를 관리하고 클라이언트 커넥션은 배열로 관리하여 여러 개를 관리하도록 구현이 돼있다.
// AActor.cpp
UNetConnection* AActor::GetNetConnection() const
{
return Owner ? Owner->GetNetConnection() : nullptr;
// 여기서 오너는 액터/폰/컨트롤러 등등이 될 수 있음.
// 코드에서 볼 수 있듯이 Owner가 지정되어 있지 않으면 통신이 안되게끔 되어 있음.
}
class UNetConnection* APawn::GetNetConnection() const
{
// if have a controller, it has the net connection
if ( Controller ) // 컨트롤러가 있다면
{
return Controller->GetNetConnection(); // 컨트롤러의 GetNetConnection()을 호출.
}
return Super::GetNetConnection(); // 없다면 AActor::GetNetConnection() 함수 호출.
}
UNetConnection* APlayerController::GetNetConnection() const
{
// A controller without a player has no "owner"
return (Player != NULL) ? NetConnection : NULL;
// 플레이어가 존재한다면 NetConnection 객체를 반환.
}
Ownership
하나의 클라이언트 커넥션은 하나의 플레이어 컨트롤러를 소유한다.
즉, 플레이어 컨트롤러의 Owning Connection은 클라이언트 커넥션이다.
PlayerController가 빙의하는 폰의 Owner 속성은 해당 플레이어 컨트롤러로 설정된다.
폰에 무기 액터가 생성되고 무기 액터의 Owner 속성에 해당 폰을 설정할 수 있다.
클라이언트 커넥션에서 부터 무기 액터에 이르는 소유 관계를 패밀리 라고도 부른다.
소유 관계 속에 있는 액터가 본인의 OwningConnection을 얻으려면 AActor::GetNetConnection() 함수를 호출하면 된다.
이 소유 관계는 후에 배울 RPC와 Property Replication과 관련이 있다.

NetDriver
언리얼 네트워크 통신에서 로우 레벨 동작들을 관리하는 클래스다.
싱글플레이에서는 넷 드라이버 객체가 생성되지 않는다.
멀티플레이에서만 UWorld::Listen() 함수를 통해 넷 드라이버 객체가 생성이 된다.
멀티플레이에 참여하는 각 PC마다 넷드라이버 객체가 생성된다.
'멀티플레이 공부' 카테고리의 다른 글
| 멀티플레이 공부(Property Replication) (0) | 2025.11.21 |
|---|---|
| 멀티플레이 공부(Remote Procedure Call, 액터 소유권, WithValidation, UnReliable, Reliable) (0) | 2025.11.20 |
| 멀티플레이 공부(NetRole, Authority, Proxy, Local Role, Remote Role) (0) | 2025.11.19 |
| 멀티플레이 공부(Server, Client, Dedicated Server 흐름도, 특징) (0) | 2025.11.17 |
| 멀티플레이 공부(멀티 실습 환경 설정) (0) | 2025.11.14 |