MSW 기본 학습 교안 7. 네트워크의 이해

bi_sz·2022년 9월 27일
0

MSW

목록 보기
7/11
post-thumbnail

네트워크의 이해 -Property와 Function의 실행 제어

MSW에서는 기본적으로 서버-클라이언트 모델을 지원하고 있다.

클라이언트 : 접속된 각각의 유저
서버 : 클라이언트의 요청을 받는 서버

각 클라이언트는 모두 서버와 연결되어 있다.

Entity를 생성하게 되면 서버와 클라이언트 모두 엔티티가 생성된다.

서버와 클라이언트가 네트워크로 연결이 되어 있긴 하지만 각각의 엔티티 (또는 컴포넌트)는 다른 객체이기 때문에 어디서 설정을 하느냐에 따라 설정값이 서로 달라질 수 있고 이로 인해 동기화 문제가 발생할 수 있다.

동기화란 ?

어느 한 쪽의 값이 달라졌을 때 양쪽의 값을 모두 바꾸는 행동을 취하는 것

기본적으로 서버는 하나이지만 클라이언트는 여러 개일 수 있다.
즉, 서버-클라이언트 관계는 위 사진과 같이 1:n의 관계 이다.

서버에서 특정 Property의 값을 바꾸면 그 Property를 갖고 있는 클라이언트의 Property 또한 전부 값이 변경된다.

반면 클라이언트에서는 독자적으로 값을 바꿔도 다른 클라이언트나 서버에 영향을 미치지 않는다.
이유는 서버와 클라이언트에 저장된 각각의 엔티티는 네트워크로 연결되어 있으나 엄현히 다른 엔티티이기 때문이다.

고전적인 방법으로는 어느 한쪽이 달라졌을 때 다른 한 쪽 또한 바꿔주는 행동을 일일히 수행해야하는데 이 과정이 상당히 번거롭다. 따라서 MSW에서는 이를 쉽게 해결하기 위해 실행제어라는 개념을 도입했다.

MSW컴포넌트에는 PropertyFunction이 존재하므로 이 두가지로 나눠 실행제어에 대해 설명한다.

Property 실행 제어

서버에서는 특정 Property의 값을 바꾸면 갖고 있는 클라이언트의 Property 또한 전부 값이 변경되는 반면, 클라이언트에서는 Property의 값을 바꿔도 서버의 Property에 영향을 미치지 않는다.

만약, 클라이언트에서 변경한 Property의 값이 서버에도 반영된다면, 서버-클라이언트 관계는 1:1이 아닌 1:n 관계이기 때문에 서버에 과부하가 오게 된다.

따라서 동기화서버->클라이언트 단방향으로 진행된다.

기본적으로 Property는 동기화 옵션을 설정할 수 있게 해준다.

[Sync] : 동기화가 되는 Property

[None] : 동기화 되지 않는 Property

동기화 옵션을 바꿨을 때 내부에서 어떤 일이 일어나는지 개발자는 알 필요가 없다.

Property 타입 중 any, table 등 동기화가 지원되지 않는 type도 있다.
Property 앞의 타입을 클릭하면 설정할 수 있는 타입들이 나오므로 클릭해 확인하면 된다.

Function 실행 제어

함수는 호출한 쪽이 서버인지 클라이언트인지에 따라 동작하는 공간이 다르다.
따라서 실행 제어를 통해 공간을 활성화 시켜주어야 한다.

공간을 활성화하면 해당 Function이 특정한 속성을 가지게 되는데, 공간 활성화로는 다음과 같이 5가지 속성이 있으며, 이렇게 함수를 요청하는 과정을 실행 제어를 통해 한 번에 보내게 된다.

  • Client : 서버가 클라이언트의 함수를 호출하면 서버와 연결된 클라이언트들에게 함수 호출을 요청하고, 연결된 클라이언트들에 있는 함수가 실행괸다.
  • ClientOnly : 클라이언트에서만 불릴 수 있으며 서버에서는 부를 수 없다.
  • Server : 클라이언트 쪽에서 서버의 함수를 호출하면 서버 쪽에 신호를 보내 서버 안에서 함수가 실행되게 한다.
  • ServerOnly : 서버에만 불릴 수 있고, 클라이언트에서는 부를 수 없다. 대부분의 로직은 서버에서 서버 기준으로 짜게 된다. 즉, 로직은 주로 서버 위주의 행위를 많이 하게 된다.
  • Multicast : 서버와 클라이언트 양쪽 모두 실행한다.

ServerOnly에서 언급했다시피, MSW에서 사용하는 로직 대부분은 서버 기반으로 돌아가게 되어있다. 서버에서 로직의 흐름을 관리하고 중간중간 변경된 사항을 각 클라이언트에 전달하는 시스템이다.

로직의 값이 변경되었을 때 변경사항을 클라이언트가 확인하고 싶으면 OnSyncProperty로 확인할 수 있다.
이 함수는 값을 받는 입장이기 때문에 ClientOnly로 설정되어 있다.

[코드 실행 예시]

<실행 순서 - 주석 참고>

MyFirstComponent {
	Property:
	Function:
		void OnBeginPlay()
		{
			log("BEGIN PLAY")
			wait(2)
			self:Server()  -- 1. 서버가 서버 메시지를 뿌flsek다.
			self:Client("HAHAHA")  -- 2. 클라이언트에서 메시지를 뿌려달라고 요청 후 바로 다음을 실행한다.
			self:MultiCast() 
			log("END")
				
		void Client( string arg1 )  -- 3. 클라이언트에 도착하면 클라이언트가 메시지를 받은 순간 요청을 실행한다.
		{
			log("CLIENT" .. arg1)
		}

		void Server()
		{
			log("SERVER")
		}

		void MultiCast()
		{
			log("MULTICAST")
		}
}

서버에서 요청했을 때 클라이언트까지 요청이 도달하는 시간이 서버가 다음 코드를 실행하는 시간보다 짧으면 클라이언트가 먼저 찍히게 된다. 즉, 요청이 클라이언트까지 도달하지 못했기 때문에 다음 코드인 end가 먼저 찍히고 클라이언트가 찍힌다.

*wait(2)를 써주지 않았을 때 Client뒤에 파라미터로 받은 문자열이 출력되지 않는 현상이 발생하는 이유
=> 서버에서 엔티티를 생성하고 클라이언트에도 엔티티가 생성되기까지 시간이 걸린다. 클라이언트에서 엔티티가 생성되는 도중에 서버에서 엔티티의 값을 넣어 전송하면 클라이언트에서 값을 받지 못하는 현상이 발생한다. 이를 타이밍 이슈라고 한다.


정리

서버가 흐름을 관장하고 클라이언트는 서버에서 받아온 것을 보여준다.
서버에 엔티티가 생성이 됐을 때 그 엔티티들이 각 클라이언트 내에도 생성된다.
특정 클라이언트 안에서 생성된 엔티티는 그 클라이언트 안에서만 생성된다.

[특정 클라이언트 안에서만 생성되는 엔티티의 대표적인 예]
  • UI
  • 입력
  • effect : effect 의 경우 보통 서버로 제어하는데 특정 클라이언트에서만 연출하고 싶을 땐 로컬 엔티티를 사용한다.
  • 최적화 : 서버에 엔티티가 너무 많을 때 비용 때문에 최적화 시 로컬 엔티티를 사용한다.

본문 : https://maplestoryworlds-developers.nexon.com/ko

0개의 댓글