Unity 실시간 멀티플레이어의 전체 환경을 다루는 이 시리즈의 첫 번째 게시물에서는 네트워킹 기본 사항과 수용 가능한 플레이어 경험 시 주요 고려 사항을 다룰 것입니다. 특히 네트워크 속도, 그 뒤에 있는 인프라, 지연 가능성 및 이러한 문제를 처리하는 방법에 대해 이야기하겠습니다.
모바일, 콘솔, PC, VR 등 대부분의 최신 게임을 고려할 때 네트워크 상호 작용은 매우 중요합니다. 간단한 멀티플레이어 게임을 만들든 야심찬 MMO를 만들든 상관없습니다. 네트워크 프로그래밍 지식이 핵심입니다.
안녕하세요 여러분, 저는 MY.GAMES의 수석 소프트웨어 엔지니어인 Dmitrii Ivashchenko입니다. "2023년 Unity 네트워킹 환경"에 관한 이 기사 시리즈에서는 네트워크 환경의 중요한 측면과 제약 조건을 다루고, 다양한 프로토콜(TCP, UDP, WebSocket 포함)을 살펴보고 Reliable UDP 프로토콜의 중요성을 강조합니다. NAT가 실시간 멀티플레이어 게임에 미치는 영향을 살펴보고 네트워크 전송을 위한 게임 데이터 준비 방법을 안내해 드립니다.
기본부터 전송 프로토콜, 네트워크 아키텍처 패턴, Unity용 기성 솔루션 등과 같은 고급 개념까지 다양한 주제를 살펴보겠습니다. 공식 Unity 솔루션과 타사 도구를 모두 분석하여 프로젝트에 가장 적합한 선택을 찾는 데 도움을 드립니다.
첫 번째 게시물에서는 네트워크 프로그래밍의 중요한 요소를 다루고 개발자가 네트워킹 기능이 있는 게임을 만들 때 자주 직면하는 장애물과 문제를 살펴보겠습니다.
인터넷은 각각 고유한 기능을 가진 다양한 장치로 구성된 복잡한 시스템입니다. 그 중 일부에 대해 이야기해 봅시다. 일반적으로 개인의 인터넷 연결은 컴퓨터나 스마트폰과 같은 장치에서 시작됩니다. 이는 로컬 네트워크와 ISP 간의 통신을 가능하게 하는 라우터나 모뎀을 통해 로컬 네트워크에 연결됩니다.
ISP에는 여러 로컬 네트워크의 트래픽을 관리하는 더 큰 라우터와 스위치가 있으며 이러한 장치는 인터넷의 백본을 구성합니다. 여기에는 대륙과 바다에 걸쳐 있는 대용량 라우터와 광섬유 케이블로 구성된 복잡한 네트워크가 포함됩니다. 백본 공급자로 알려진 별도의 회사가 이 백본을 유지 관리할 책임이 있습니다.
또한 데이터 센터에는 웹사이트, 애플리케이션, 온라인 서비스가 상주하는 강력한 서버가 있습니다. 귀하가 웹사이트나 온라인 서비스에 대한 액세스를 요청하면 귀하의 요청은 이 광범위한 네트워크를 통해 관련 서버로 이동한 후 동일한 경로를 따라 데이터가 다시 전송됩니다.
TCP, UDP, 릴레이 서버 및 실시간 멀티플레이어 게임 개발의 세계에 뛰어들기 전에 네트워크 시스템 전체를 확실하게 이해하는 것이 중요합니다. 여기에는 허브 및 라우터와 같은 장치의 역할 및 기능을 이해하고 이러한 장치 및 매체의 작동으로 인해 발생할 수 있는 잠재적인 문제에 대한 인식이 포함됩니다.
네트워크 기술은 실제 세계와 분리되지 않으며 대역폭, 대기 시간, 연결 안정성 등 여러 가지 물리적 제한이 적용됩니다. 이러한 모든 요소는 네트워크 게임을 개발할 때 고려해야 할 중요합니다.
이러한 기본 원칙과 제약 조건을 이해하면 게임의 성공적인 네트워크 통합에 필요한 가능한 솔루션과 전략을 더 잘 평가하는 데 도움이 됩니다.
대역폭은 특정 기간 동안 네트워크를 통해 전송할 수 있는 최대 데이터 양입니다. 데이터 전송 속도는 사용 가능한 대역폭에 따라 직접적으로 달라집니다. 즉, 대역폭이 많을수록 더 많은 데이터를 동시에 업로드할 수 있습니다.
대역폭은 초당 비트 수로 측정되며 대칭(업로드 및 다운로드 속도가 동일함)과 비대칭(업로드 및 다운로드 속도가 다름)의 두 가지 유형이 있습니다.
대칭 연결은 일반적으로 광섬유 네트워크와 같은 유선 네트워크에 사용되는 반면, 비대칭 연결은 모바일 데이터의 경우와 같은 무선 네트워크에 사용됩니다.
대역폭은 일반적으로 초당 비트(bps) 또는 초당 메가비트(Mbps)와 같은 배수로 측정됩니다. 대역폭이 높다는 것은 더 짧은 시간에 더 많은 데이터를 전송할 수 있다는 것을 의미하며, 이는 실시간 멀티플레이어 게임에 절대적으로 필요합니다.
RTT(Round-Trip Time)는 데이터 패킷이 발신자에서 수신자로 이동한 다음 다시 돌아오는 데 걸리는 시간을 측정합니다. 이는 플레이어가 게임 플레이 중에 경험할 수 있는 지연 시간에 영향을 미치기 때문에 네트워크 게임에서 필수적인 지표입니다.
RTT가 높으면 플레이어는 게임 플레이에 부정적인 영향을 미칠 수 있는 지연을 경험할 수 있습니다. 따라서 게임 개발자는 RTT를 최소화하여 더욱 부드럽고 반응성이 뛰어난 게임 플레이 경험을 제공하기 위해 노력해야 합니다.
네트워크 지연(흔히 "지연"이라고도 함)은 보낸 사람에서 받는 사람으로 데이터 패킷을 전송하는 데 필요한 시간입니다. 1인칭 슈팅 게임과 같이 응답성이 요구되는 게임에서는 작은 네트워크 지연이라도 게임 플레이에 큰 영향을 미칠 수 있습니다.
데이터가 빛의 속도에 가까운 속도로 전송되더라도 거리가 여전히 시스템에 영향을 미치고 지연이 발생할 수 있습니다. 인터넷이 작동하는 데 필요한 인프라로 인해 지연이 발생하는 경우가 많으며 이러한 지연은 제거할 수 없습니다. 이는 물리적 케이블을 통한 전송, 라우터 및 스위치와 같은 네트워크 장치의 지연, 송수신 장치의 처리 지연과 관련된 이유로 발생할 수 있습니다. 즉, 이 인프라는 지연을 줄이기 위해 최적화될 수 있습니다.
데이터 전송 수단이 네트워크 대기 시간에 어떤 영향을 미치는지 이야기해 보겠습니다. 광섬유를 통해 빛으로 전송되는 데이터는 정확히 빛의 속도로 전송되지 않습니다. 실제로 광섬유의 빛은 진공 상태에서보다 느리게 전송됩니다. 광섬유의 재질이 속도에 영향을 미치기 때문입니다.
(빛의 최대 속도는 대략 초당 2억 9900만 미터 또는 시간당 18만 6천 마일이지만, 이는 이상적인 진공 조건에서만 가능합니다.)
따라서 광섬유를 사용하면 상대적으로 빛이 더 느린 속도로 전송됩니다. 또한 광섬유는 구리선보다 대역폭이 더 크고 간섭에 덜 민감하기 때문에 구리 배선을 통해 전송되는 데이터는 광섬유에 비해 상당히 낮습니다.
노선 | 거리 | 시간(빛의 속도) | 시간(광섬유) | RTT |
---|---|---|---|---|
암스테르담 - 런던 | 360km | 1ms | 2ms | 4ms |
암스테르담 - 뉴욕 | 5850km | 20ms | 29ms | 58ms |
암스테르담 - 베이징 | 7800km | 26ms | 39ms | 78ms |
암스테르담 - 시드니 | 16700km | 56ms | 83ms | 166ms |
위 표에서는 데이터 패킷이 도시 간 큰 원을 그리며 광섬유를 통해 전송되고 있다고 가정하지만 실제로는 그런 경우가 거의 없습니다. 데이터 패킷의 라우팅에는 대부분 중간 지점("홉")이 많아 데이터 전달 시간이 크게 늘어날 수 있습니다. 각 중간 지점마다 지연이 추가되고 실제 이동 시간이 크게 늘어날 수 있습니다. 광섬유를 통해 전송되는 데이터 패킷(빛의 속도에 가까운 속도)은 암스테르담에서 시드니까지 왕복 여행을 완료하는 데 150밀리초 이상이 필요합니다.
사람들은 밀리초 지연에 특별히 민감하지 않지만, 연구에 따르면 100-200ms에 도달할 때쯤에는 인간의 두뇌에서 지연이 이미 눈에 띄는 것으로 나타났습니다. 300ms를 초과하면 인간의 뇌는 이를 느린 반응으로 인식합니다.
100ms를 초과하지 않도록 네트워크 대기 시간을 줄이려면 지리적으로 최대한 가까운 사용자가 콘텐츠를 사용할 수 있어야 합니다. 우리는 데이터 패킷의 통과를 신중하게 제어하고 혼잡을 최소화하면서 명확한 경로를 제공해야 합니다.
지터는 네트워크 지연의 변형 또는 "변동"입니다. 이는 연속적인 데이터 패킷 사이의 지연 시간의 변화를 설명합니다. 데이터 패킷이 불규칙한 간격으로 도착하는 경우 이는 네트워크 전송이 불안정함을 나타냅니다. 이는 네트워크 정체, 트래픽 변화, 장비 결함 등 다양한 요인으로 인해 발생할 수 있습니다.
평균 지연이 허용 가능한 것으로 간주되더라도 높은 지터는 특히 온라인 게임과 같은 실시간 애플리케이션이나 지연 일관성이 필수적인 인터넷 전화 통신과 관련된 애플리케이션에서 문제를 일으킬 수 있습니다.
지터의 양이 너무 크면 플레이어는 게임 캐릭터나 개체를 움직일 때 지연이나 "말더듬"을 경험할 수 있습니다. 이로 인해 데이터 패킷이 목적지에 도달하지 못하거나 너무 늦게 도착하여 유용하지 않게 되는 패킷 손실이 발생할 수도 있습니다.
지터는 게임의 전반적인 공정성에 영향을 미칠 수도 있습니다. 예를 들어 한 플레이어는 지터가 높고 다른 플레이어는 그렇지 않은 경우 해당 플레이어의 작업이 더 빨리 등록되고 표시되므로 후자가 이점을 갖게 됩니다.
패킷 손실은 하나 이상의 데이터 패킷이 대상에 도달하지 못하는 상황입니다. 이는 네트워크 문제, 트래픽 과부하, 장비 문제 등 다양한 이유로 발생할 수 있습니다.
이러한 정보가 관련된 실시간 게임에서는 패킷 손실로 인해 캐릭터가 "정지"되거나 개체가 사라지거나 플레이어 간의 게임 상태가 불일치하는 등 눈에 띄는 문제가 발생할 수 있습니다.
패킷 손실은 전송 중에 필요한 정보가 손실될 수 있으므로 게임 플레이가 완전히 중단될 수 있습니다.
따라서 패킷 손실에 대처하거나 게임 플레이에 미치는 영향을 최소화하는 메커니즘을 개발하는 것이 중요합니다.
틱율, 즉 시뮬레이션 속도는 게임이 매초마다 데이터를 생성하고 관리하는 빈도를 나타냅니다. 틱 동안 서버는 수신된 데이터를 처리하고 시뮬레이션을 수행한 후 결과를 클라이언트에 보냅니다. 그런 다음 서버는 다음 틱까지 휴식을 취합니다. 빠른 틱 속도는 클라이언트가 서버에서 새로운 데이터를 더 빨리 가져오고 플레이어와 서버 간의 지연을 줄이고 적중 등록 응답성을 향상한다는 것을 의미합니다.
60Hz의 틱 속도는 시뮬레이션 단계 사이의 시간을 줄여 지연이 줄어들기 때문에 30Hz보다 더 효율적입니다. 또한 이 속도를 통해 서버는 초당 60개의 업데이트를 전송할 수 있으므로 클라이언트와 서버 간의 왕복 지연이 약 33ms(클라이언트에서 서버로 -16ms, 서버에서 클라이언트로 -16ms)만큼 줄어듭니다.
그러나 서버가 각 틱 속도에 할당된 간격 내에서 틱을 처리하는 데 어려움을 겪을 때 러버 밴딩, 플레이어 순간 이동, 히트 거부, 물리적 오류와 같은 게임 플레이 문제가 발생할 수 있습니다. 예를 들어, 서버가 60Hz 틱 속도로 설정되어 있지만 각 틱에 사용 가능한 약 16.67밀리초(1초/60) 내에 필요한 시뮬레이션 및 데이터 전송을 완료할 수 없는 경우 이러한 문제가 발생할 수 있습니다.
지연 및 패킷 손실에 대한 섹션에서 논의한 것처럼 지연은 해결해야 할 문제이며 지터는 원활한 게임 환경을 만드는 것을 더욱 어렵게 만듭니다.
지연을 무시하고 이를 완화하기 위한 조치를 취하지 않으면 결국 "멍청한 터미널"이 될 것입니다. 멍청한 터미널은 클라이언트에게 보여주는 시뮬레이션을 이해할 필요가 없습니다. 대신 클라이언트에서 서버로 입력 데이터만 보내고 서버에서 결과 상태를 받아 표시합니다.
이 접근 방식은 정확성을 우선시하여 올바른 사용자 상태가 항상 표시되도록 합니다. 그러나 다음과 같은 몇 가지 단점이 있습니다.
따라서 "멍청한 터미널" 접근 방식은 정확한 상태 표현을 보장하지만 본질적인 한계로 인해 게임 경험의 품질을 잠재적으로 낮출 수 있습니다.
RTT 진동과 지터의 혼돈이 결합되면 결과적으로 바람직하지 않은 게임 경험이 발생합니다. 서버의 업데이트가 자주 발생하지 않거나 네트워크 상태가 좋지 않으면 시각적으로 불안정해질 수 있습니다. 그러나 클라이언트 측 보간과 같이 지연 및 지터의 영향을 최소화하는 방법이 있습니다.
클라이언트 측 보간을 사용하면 클라이언트는 단순히 서버에서 전송된 위치에 의존하는 대신 시간이 지남에 따라 개체의 상태를 원활하게 보간합니다. 이 방법은 서버에서 전송된 실제 상태 간의 전환만 원활하게 하기 때문에 주의가 필요합니다.
신뢰할 수 있는 서버가 있는 토폴로지에서 클라이언트는 일반적으로 서버의 실제 모델링 상태 뒤에 있는 RTT의 대략 절반에 해당하는 상태를 표시할 수 있습니다. 그러나 클라이언트측 보간이 올바르게 작동하려면 서버에서 전송된 마지막 상태보다 지연되어야 합니다. 이로 인해 보간 기간 동안 지연이 증가합니다. 끊김 현상을 방지하려면 이 기간은 패킷 전송 기간보다 짧아야 합니다. 클라이언트가 이전 상태로의 보간을 마치면 새 상태를 수신하고 프로세스를 반복합니다.
비주기적인 상태 업데이트의 영향을 최소화하기 위해 일부 개발자는 DR(Dead Reckoning)이라고도 알려진 추정 방법을 사용합니다. 이 기술에는 마지막으로 알려진 값을 기반으로 게임 개체의 미래 위치, 회전 및 속도를 예측하는 작업이 포함됩니다. 예를 들어 플레이어가 개체의 현재 위치, 회전 및 속도와 함께 세 번째 프레임마다 패킷을 보내는 경우 Bolt의 외삽 알고리즘은 새 데이터가 도착할 때까지 다음 세 프레임 동안 개체가 어디에 있을지 추정할 수 있습니다.
이 경우 새 패킷이 예상대로 도착하지 않으면 동일한 추측 방법을 계속 사용할 수 있다는 점에 유의하는 것이 중요합니다. 그러나 미래를 추측하는 기간이 길어질수록 오류를 범할 가능성이 높아집니다. 이 문제를 해결하기 위해 DR 알고리즘은 실제 데이터가 수신되면 "투영 속도 혼합"을 활용하여 수정합니다.
추정은 게임에서 인위적인 패킷 지연의 필요성을 줄여 플레이어에게 실시간 동작을 더 빠르게 표시합니다. 또한 많은 플레이어가 참여하는 게임에서 작업할 때 손실되거나 누락된 패킷을 보다 효과적으로 처리합니다. 즉, 위치, 회전, 속도 정보가 누락되어도 게임 플레이가 지연되지 않습니다.
DR은 도움이 될 수 있지만 보간만큼 정확하지는 않습니다. 또한, FPS 게임을 플레이하고 지연 보상을 통해 권위 있는 촬영을 하려는 경우 DR을 사용하는 것이 어려울 수 있습니다. 이는 값 추정을 포함하는 외삽으로 인해 각 플레이어가 화면에서 보는 내용이 달라질 수 있기 때문입니다. 보간된 값을 사용하는 경우 수직으로 움직이는 플레이어를 직접 겨냥해도 여전히 슛을 놓칠 수 있습니다.
클라이언트 측의 보간 및 추정을 통해 지연이 줄어들지만 게임은 여전히 "느린" 느낌을 받을 수 있습니다. 이것이 "클라이언트 측 예측"이 필요한 곳입니다. 버튼을 누른 직후 플레이어 캐릭터가 움직이기 시작하여 느린 느낌을 제거합니다. 올바르게 수행되면 이 예측은 서버의 계산과 거의 동일합니다.
클라이언트 측 예측은 서버와 클라이언트가 보는 것 사이에 차이를 발생시킵니다. 이로 인해 "예기치 않은" 시각 효과가 발생할 수 있습니다. 처리되지 않은 플레이어 작업을 고려하고 각 서버 업데이트 후에 이를 다시 적용하는 것이 중요합니다.
개선에도 불구하고 서버 업데이트와 플레이어가 이를 확인하는 순간 사이에는 여전히 상당한 지연이 있습니다. 예를 들어, 이는 플레이어가 완벽한 슛을 성공했지만 다른 플레이어의 오래된 위치를 겨냥했기 때문에 실패하는 시나리오로 이어집니다. 이것이 지연 보상(Lag Compensation)으로 알려진 논쟁 영역이 시작되는 곳입니다.
지연 보상은 예를 들어 한 선수가 완벽한 슛을 성공했지만 다른 선수의 "오래된" 위치를 겨냥했기 때문에 빗나가는 문제를 해결하기 위한 논란의 여지가 있는 기술입니다.
지연 보상의 원칙은 서버가 언제든지 세계 상태를 다시 생성할 수 있다는 것입니다. 서버가 샷에 대한 정보가 포함된 데이터 패킷을 수신하면 샷 순간의 세계를 재현하고 히트 여부를 결정합니다.
안타깝게도 지연 보상은 부정행위에 취약합니다. 서버가 플레이어가 보낸 타임스탬프를 신뢰하는 경우 플레이어는 나중에 샷을 보내지만 그보다 얼마 전에 수행된 것처럼 속임으로써 서버를 "속일" 수 있습니다.
이러한 이유로 지연 보상은 피해야 합니다. 클라이언트 측에서 위에서 설명한 세 가지 기술은 서버에서 클라이언트로의 신뢰를 의미하지 않으며 이와 같은 남용에 취약하지 않습니다.
이 시리즈에서는 가장 빠르고, 가장 컴팩트하며, 안정적인 방식으로 데이터를 전송하는 방법을 배우면서 이러한 모든 기술을 더 자세히 살펴보겠습니다.
플레이어는 다양한 라우터 모델을 사용하는 다양한 장치에서 게임을 하며 다양한 공급자의 서비스를 받게 됩니다. 때로는 고속 인터넷을 위해 광섬유 케이블을 통해 연결되기도 하고, 때로는 Wi-Fi 연결이나 3G 모바일 인터넷을 사용할 수도 있습니다. 이는 네트워크 상태가 크게 달라질 수 있으며 대기 시간, 패킷 손실 및 전반적인 연결 안정성에 영향을 미칠 수 있음을 의미합니다. 게임 개발자로서 최상의 게임 경험을 보장하기 위해 이러한 다양한 환경을 이해하고 네트워크 처리를 설계하는 것이 중요합니다. 의심할 바 없이 어려운 작업이지만 적절하게 수행된 이러한 관행을 높은 수준으로 구현하는 것은 성공적인 멀티플레이어 게임을 나머지 게임과 차별화하는 요소입니다.
다음 섹션에서는 TCP, UDP 및 WebSocket과 같은 주요 데이터 전송 프로토콜에 대해 설명합니다.