Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

게임 개발 메모장

[ UE5 ] 커넥션과 오너십 본문

언리얼 엔진/Network

[ UE5 ] 커넥션과 오너십

Dev_Moses 2023. 12. 25. 23:14

 

 

서버 섹션에서 플레이어 컨트롤러부터 전달된 어떤 명령은 

넷커넥션 객체에 의해서 관리가 되는데,

이 넷커넥션은 상위에서 네트워크 통신을 담당하는 클래스이다.

 

상위 명령어를 로우레벨 데이터로 변활할 수 있는 기초 작업을 진행해준다.

전체적인 관점에서 네트워크가 원활하게 진행할 수 있도록

어떤 밴드위스라든지 대역폭이라든지 흐름을 조절하는 역할도 함께 담당해준다.

 

그 아래 NetDriver는 NetConnection에서 정돈된 데이터를

실제 네트워크상으로 보내는 로우 레벨 기능을 제공한다.

 

이렇게 해서 NetDriver를 통한 데이터가 클라이언트에 전달이 되면

클라이언트는 거꾸로 NetConnection을 거쳐서 액터에 명령을 내리게 된다.


 

서버가 시작하는 과정

처음에는 StandAlone의 모드로 시작했다가 후에 리슨 서버로 변경 된다.

이러한 모드의 값은 현재 있는 월드에 NetDriver가 있는지로 판단을 하게 되는데

내부적으로 월드가 구동될 때 Listen 함수가 호출되면 월드의 NetDriver 객체가 만들어지고

이것으로부터 네트워크 통신이 시작된다.

 

월드 소스의 InternalGetNetMode 함수를 통해서 NetMode가 어떻게 파악되는지 살펴볼 수 있다.

월드의 Listen 함수를 보고 서버가 어떻게 시작 되는지를 살펴 볼 수가 있다.

 

 

통신을 담당하는 넷드라이버가 설정이 되어 있으면 클라이언트 아니면 서버 

둘 중에 하나다 라고 return을 하는 것을 볼 수 있다.

 

현재 서버라면 현재 월드에서 Run as dedicated라고 내가 실행했다고

그러면 dedicated 서버를 반환을 해준다.

 

하지만 일반적인 경우일 때 만약 데이케이티드 서버로 실행이 안되었다면

서버인 경우에는 GIsClient (내가 플레이어로서 게임에 참여하는

어플리케이션이다 이것을 판별해주는 전역 변수이다.)

 

그러니까 게임에 참여하는 것은 당연히 리슨 서버가 되겠고, 

게임에 참여하지 않으면 데디케이티드 서버가 된다.

 

그리고 서버가 아니면 클라이언트로 간주해준다.

 

넷드라이버는 커넥션을 관리해주는 것이기 때문에 만약에 넷드라이버가 없다고 하면

대부분 스탠드얼론이라고 생각한다.

 

 

리슨 함수에서 하는 역할은 넷드라이버를 만들어 주는 것

넷드라이버를 만들어 주게 되면

 

넷드라이버가 있으면 클라이언트, 서버, 데디케이티드서버 이 셋 중에 하나가 된다.

 

그렇게 때문에 우리가 GetNetMode 함수를 호출해서 네트워크 모드를

파악할 때 중간에 바뀌는 이유가 이 넷 드라이버의 유무에 따라서

바뀌게 된다라고 이해 하면 된다.


 

 

언리얼 엔진은 이러한 특징을 사용해서 현재 어플리케이션이

서버 모드인지 클라이언트 모드인지를 구분한다.

 

 

서버 커넥션이 NULL 이라면 서버라는 얘기다.

 

 

결과 화면들

 

처음 시작할 때는 넷드라이버가 지금 없는 상태다.

아직 자기 자신 클라이언트로서만 넷드라이버가

활성화되지 않은 상태에서 로그인 했기 때문에

지금 포스트 로그인이 될지라도 넷드라이버가 활성화 되지 않았다는 로그가 찍혔다.

 

아직 리슨이 호출되지 않은 상태인 것이다.

이때 하지만 조금 있다가 Listen이 호출되어서

이제 서버로서의 기능을 수행하고 있을 것이다.

이제 클라이언트가 들어오도록 해보자

 

 

 

클라이언트가 들어왔을 때 로그에 포스트 로그인에서

클라이언트 커넥션 하나가 찍히는 게 보인다.

 

7번이라는 이름으로 IP 커넥션이 하나 만들어 진 걸 볼 수가 있고

클라이언트에서는 지금 6번에서 서버 커넥션의

객체가 만들어진 것을 확인 할 수 있다.

 

클라이언트 하나 더 추가를 해보면 

이렇게 되면 포스트 로그인 단계에서 두 개가 찍히게 된다.

 

 

 

지금 현재 모든 것을 다 출력 하기 때문에

서버에서는 클라이언트 커넥션이 두 개가 찍히는 것을 볼 수 가있고

 

클라이언트 2에서는 서버 커넥션 하나만 찍힌다.

이렇게 해서 넷드라이버가 가지고 있는 커넥션 정보가 어떻게 만들어 지는지 한번 살펴봤다.

 


 

커넥션이라고 하는 것은 모든 네트워크를 주고 받는 통신망으로 생각하면된다.

여기서 주고 받는 데이터를 패킷이라고 하는데 이 패킷은 단순한 어떤 데이터를 전달하는

데 사용하지만 언리얼의 아키텍쳐가 제공하는 다양한 기능을 지원하려면 꽤나 복잡한

규약을 지정해야 한다.

 

우리가 직접 지정할 필요는 없고 언리얼 엔진이 다 만들어놨는데 이 데이터의 경우에는 

용도에 따라 다르게 사용된다.

 

어떤 데이터는 액터 정보를 네트워크로 복제하는 데 사용하고,

어떤 데이터는 플레이어의 보이스, 음성을 전달하는데 사용할 수 있다.

 

이렇게 용도에 따라 데이터를 구분하는 접속 단위를 채널이라고 한다.

하나의 커넥션은 다수의 채널을 가진다고 생각하면 된다.

이 채널에서 용도에 맞게 정리된 데이터 묶음을 번치라고 한다.

만약 우리가 효율적인 데이터 전송을 위해서 다수의 속성값을 묵어서

한 번의 네트워크로 보낸다고 생각해 보면

 

이 경우 그 데이터 묶음을 번치라고 생각하면 된다.

이렇게  상위 개념으로 갈수록 상위 개념에서 네트워크를 담당하는 담장자 액터를 

지정해야 되는데 이것이 플레이어 컨트롤러다.

 

현재 어플리케이션이 관리 하고 있는 커넥션의 수만큼 어플리케이션에서

만들어 진다.

 

그렇다면 서버의 경우에는 여러 개의 플레이어 컨트롤러가 만들어 질 것이고

클라이언트에는 딱 하나만 만들어진다.

 

이러한 플레이어 컨트롤러는 각각 커넥션에 대한 Ownership 즉, 소유권을 가진다.


 

 

 

플레이어 컨트롤러 빙의 과정

 

내가 빙의할 폰에 PossessedBy라는 함수가 호출되는 것을 볼 수 있는데,

그래서 이 함수를 호출을 해서 어떻게 Owner가 변경되는지를 살펴보자

 

Super::PossessedBy(NewController);

가 호출 되기 전과 후의 액터의 오너가 어떻게 변하는지 살펴보자

 

포스트 로그인에서 빙의가 시작된다.

빙의가 시작되고 PossessedBy 함수가 호출되는데

처음에는 Owner가 설정이 안 되어있다.

그런데 Super 함수를 실행하고 나서

Owner가 컨트롤러로 설정되어있는 것을 확인 할 수 있다.

 


클라이언트를 추가해보면 

 

 

서버에서 동일하게 1번 클라이언트에 대한 Owner가 Possesed 빙의 함수에 의해서

설정되는 것을 확인 할 수가 있다.

 

그런데, 클라이언트에서도 Owner가 설정이 되어야 한다.

지금 서버에서만 Owner가 설정되어 있는데 클라이언트도

물론 Owner가 설정되어 있을 것

같은데 이 타이밍에 모든 셋업이 끝난 타이밍인

PostNetInit 타이밍에서 Owner가 설정이 되어 있을 것이다.

 


 

플레이어에다 PostNetInit 함수를 만들어서 호출을 해주고 

동일하게 로그를 찍어 보자

 

네트워크의 Owner, 플레이어 같은 경우에는 언제 Owner가 바뀌는지?

PossesedBy 함수를 호출하지 않는데

그때는 플레이어가 가지고 있는 Owner의 값이 복제가 된다.

 

그래서 Owner의 값이 변경이되면

OnRep_Owner() 함수가 호출된다.

 

Actor.h

 

Owner의 속성이 변경이 되면 이 함수가 호출이 된다.

 

그렇기 때문에 클라이언트는 PossesedBy 함수가 호출되지 않고

OnRep_Owner 함수에 의해서 네트워크에서 Owner 값이 동기화가 되는 것이다.

그리고 나서 Owner가 설정된다.

 

 

클라이언트를 추가하면 클라이언트에는 PossesedBy 함수가 호출되지 않았고

플레이어가 복제가 될 때 플레이어의 경우에는 클라이언트에 대한 플레이어도 있지만

 

이 서버의 플레이어도 이쪽에 복제가 된다.

 

그런데 서버의 플레이어의 경우에는 지금 Owner가 리플리케이션되지 않은 상태로 초기화가 된다.

 

하지만 이 클라이언트 자체는 이 서버에서 생성된 플레이어의 Owner 값이 복제가 되면서 

 OnRep_Owner 함수가 호출이 된다.

 

 

캐틱터 플레이어 0번에 대해서만 이 Owner가 복제가 되면서 Owner가 설정되는 것을 확인 할 수 있다.

 

 


 

 

 

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

 

액터와 그 접속 소유

멀티플레이어에서 서버의 역할에 대한 개요입니다.

docs.unrealengine.com

https://www.inflearn.com/courses?s=%EC%9D%B4%EB%93%9D%EC%9A%B0

 

이득우 의 검색 결과 - 인프런 | 강의

관심 있는 강의가 있다면 지금 당장 시작하세요! 인프런은 언제나 당신의 성장을 응원합니다. - 학습하기 | 인프런

www.inflearn.com