지난번에 이어서 Tucker님의 게임 네트워킹 이해를 시청한 내용을 정리해보겠다.
1. P2P, Relay Server, 홀펀칭
영상에서 먼저 P2P에 대해 설명하기 전에 인터넷의 유래에 대한 설명을 먼저 한다.
인터넷이 군사목적으로 탄생했다는 것은 알고 있었지만, 조금 더 재밌는 내용을 알게 되었다. 요약하자면, 미국과 소련의 냉전기에 서로에게 미사일 혹은 핵 타격을 안정적으로 수행하기 위해 인터넷 통신망이 구축되었다는 것이다. 만약 미사일 발사 회선이 하나로만 이루어져있으면 적국의 스파이가 해당 회선을 끊어버리고 선제 타격을 하는 경우 대응을 못하지만, 회선을 복잡하게 구축해서 하나의 회선에 문제가 생겨도 다른 회선을 통해 접근할 수 있다면 대응 사격을 할 수 있을 것이다. 따라서 선제 공격을 하면 대응 사격을 받을 것이므로, 서로가 서로를 견제하며 공격하지 못하는 상황이 되는 것이다. 이 이야기를 왜 하셨을까 생각해봤는데, 이 직후에 IPv4 이야기가 등장한다. 아마 당시에는 군사 목적으로 쓰였기 때문에 많은 IP주소가 필요하지 않았다는 이야기를 하려고 하신 것으로 추정된다.
아무튼, IPv4는 약 43억 개의 IP주소를 할당할 수 있고, 현대에 와서는 컴퓨터가 너무 많아져서 43억개로는 부족하여 IPv6로 넘어간다고 배웠는데, 마냥 그렇지만은 않은 것 같다. 최근에는 게이트웨이와 같은 큰 단위의 기기에만 고정 IP를 할당하고, 그 밑에 있는 기기에는 private한 가상의 IP주소를 부여한다는 것이다. 이렇게 하면 IP주소의 여유분도 확보할 수 있고, 내부 컴퓨터를 외부로부터 숨겨주는, 보안의 기능도 할 수 있다고 한다. 다만, 이 경우 문제가 생기는데 내부에 있는 기기가 가상의 IP 주소를 가지고 있기 때문에 외부에서 IP 주소로 해당 컴퓨터 연결할 수 없다는 것이다.
그러면 외부에 있는 컴퓨터가 게이트웨이 속의 숨겨진 컴퓨터에 어떻게 연결을 할 수 있을까? 그것은 바로 숨겨진 컴퓨터가 먼저 외부의 고정 IP를 가진 컴퓨터에 패킷을 보내는 것이다. 이 경우, 중간에 있는 게이트웨이와 같은 NAT 장비가 테이블을 만들어서 내 private IP주소와 목적지 IP 주소를 저장한다. 그리고 이것을 포트번호로 기억한다. 이것을 포트포워딩이라고 한다. 그러면 외부에 내가 속한 게이트웨이의 고정 IP주소와 포트 번호를 전달하기 때문에, 해당 게이트웨이에 포트 번호와 함께 전송을 보내면 게이트웨이가 포트 번호를 참조하여 private IP주소로 전달을 해주는 것이다. 그리고 포트포워딩은 여러 차례 될 수 있다. 게이트웨이가 라우터를 포트포워딩하고, 라우터가 공유기를 포트포워딩하고, 공유기가 우리들이 쓰는 일반적인 컴퓨터를 포트포워딩하는 것이다.
그래서 P2P란 무엇인가 하면, Peer To Peer의 줄임말로, 클라이언트와 클라이언트가 직접 연결하는 방식을 말한다. 이 방식의 문제는, 위에서 설명했듯 고정 IP주소가 없는 클라이언트에게 먼저 패킷을 보내는 것이 불가능하다는 것이다. 때문에 두 클라이언트가 STUN 서버라고 하는 고정 IP주소를 가진 서버에 패킷을 보낸다. 그러면 STUN 서버는 각각이 속한 게이트웨이의 public IP주소와 포트 번호를 상대방에게 알려주는 것이다. 그러면 서로 연결할 수 있게 되는 것이다. 이것을 홀펀칭이라고 한다. 그런데 여기서 또 문제가, 게이트웨이가 포트포워딩을 할 때, 출발지는 물론이고 목적지도 저장한다는 것이다. 즉, 해당 포트 번호는 STUN서버가 목적지이기 때문에 다른 곳에서 보낸 패킷을 전달하지 않을 수 있다는 것이다. 이것은 순전히 게이트웨이 마음이라고 한다. Relay 서버는 TURN 서버라고도 하는 것 같은데, 간단하게 서버가 플레이어 간 보낸 패킷을 서로에게 전달해주면 되기 때문에 이런 문제가 발생하지 않는다. 그래서 먼저 STUN 서버를 통해 홀펀칭을 시도해보고, 실패하면 TURN 서버를 사용한다고 한다. 홀펀칭 또한 UDP를 기반으로 한 기술인데, Reliable UDP와 마찬가지로 옛날에는 일부 큰 기업에서만 사용하던 비밀 기술이었으나, 현재는 널리 퍼진 기술이라는 것 같다.
2. Deterministic과 게임핵
Deterministic 방식은 이전에 정리했듯 같은 입력이 들어오면 같은 처리를 보장해주는 것이다. 즉, 입력에 강하게 의존한다는 것이다. 영상에서는 예시로 FPS를 들었는데, 내 입장에서는 잘 이해가 되지 않아서 내가 들으면서 생각했던 격투 게임으로 예를 들어보겠다. 영상에서 얘기한 것과 거의 부합하는 내용인 것 같은데, 예시가 틀릴 수도 있다. 철권같은 격투 게임의 경우 적에게 공격을 당하면 피격 모션을 재생하며 공중에 붕 뜨거나 날아간다. 이 도중에 상대방을 공격할 수 없다. 아마 이 도중에 공격 버튼을 누르면 내부 검사를 통해 입력이 무시되어 상대방에게 전달되지 않겠지만, 내부의 검사 코드를 조작하여 피격 중인데도 불구하고 공격 버튼 입력이 상대에게 전달됐다고 해보자. 아마 상대는 신나게 콤보를 때려넣다가 갑자기 맞는 상황이 연출될 것이다. 때문에 이런 입력을 검증하는 작업이 필요하다.
P2P 방식으로 연결된다면, 상대 클라이언트에서 해당 입력을 검증한다. 이 경우, 클라이언트는 게임의 Rule과 현재 상태 등을 가지고 있기 때문에 상대방이 공격할 수 없는 상황이라는 것을 알고 있고, 해당 입력이 부정한 입력이라는 것을 캐치해낼 수 있다.
Relay 서버를 통하는 방법을 사용한다면, 중계 서버에서 부정을 감지하기 위해서는 게임의 Rule과 현재 상태를 가지고 있어야 한다. 단, 이 경우에는 하나의 중계 서버가 여러 개의 게임을 서비스할 수 없다는 단점이 있다. 그렇기 때문에 하나의 중계 서버를 통해 여러 개의 게임을 서비스하기 위해 중계 서버는 패킷을 서로에게 전달해주는 역할만을 하는 것이 좋다는 것 같다.
어떤 방식을 이용하든 검증하는 방법이 있을텐데, 이 검증하는 방법을 악용할 수도 있다는 모양이다. 가령 플레이어가 1초에 10m를 움직일 수 있다고 하면, 오차 범위로 12~13m까지는 허용되게끔 한다는 것이다. 10m로 칼같이 잡아버리면 작은 오류로 아주 작은 오차가 발생해도 핵으로 인식할 수 있기 때문이다. 때문에 핵은 이런 것을 역이용해서 걸리지 않을 정도로만 빠르게 움직이게 할 수도 있다는 것이다.
또, 해킹에는 외부툴을 이용해서 해킹을 하는 외부 해킹이 있고, 내부의 코드를 조작하는 내부 해킹이 있다고 한다. 외부 해킹은 외부 툴을 막는 nProtect 등의 프로그램 등을 사용해서 해킹 프로그램을 실행하지 못하게 하는 방법이 있다. 내부 해킹의 경우, exe파일이 게임의 코드를 기계어로 번역한 것이기 때문에, 이 기계어를 역어셈블리에 넣고 복원하여 코드를 변조시키는 방법을 사용한다고 한다. 이를 막기 위해서 파일 사이즈를 검증하기도 하고, 코드 전체를 Hash코드화해서 Hash코드가 변경되지 않았는지 확인하는 방법도 있다. 또, 코드를 암호화하여 실행할 때 복호화하는 방식도 있다고 한다. 어찌되었든, 해킹의 방어가 강해질수록 해커의 공격도 강해지고, 결국 해커에게 선공권이 있기 때문에 핵이 뚫리는 것은 어쩔 수 없는 일이라는 것 같다. 단, 뚫릴 때마다 방어를 강화하여 겹겹이 씌워 해커를 귀찮게 만든다고 한다.
Server Authority 방식에 대한 영상도 보았는데, 내용이 조금 적고 다음 내용과 연계되는 내용인 것으로 보여 다음에 정리할 때 같이 정리해야겠다.
'개발 > 공부' 카테고리의 다른 글
Race Condition, 동기화, 임계 영역, 스핀락, 뮤텍스, 세마포어 (0) | 2023.05.02 |
---|---|
게임 네트워킹의 이해 3 - Socket Programming, MMORPG 서버 구조 (0) | 2023.05.01 |
게임 네트워킹의 이해 1 - 네트워킹, UDP/TCP, Deterministic-Delay/Rollback 방식 등 (0) | 2023.04.27 |
메모리 관리에 대한 탐구 (1) (0) | 2022.12.29 |
회전/첫 번째 원소 삭제에 관한 탐구 (0) | 2022.12.20 |