해당 글은 게임 서버 프로그래밍 교과서의 내용을 정리한 글입니다.

UML

프로그램 구조 명세를 표현하는 대표적인 수단
파워포인트도 괜찮다.

UML 시퀀스 다이아그램

객체와 메시지를 사용한다. 네모 박스로 표현한다.
객체는 상호 작용의 주체이며, 메시지는 상호작용의 내용에 해당한다. 화살표로 표현한다.

이러한 방법으로 객체 사이에 메시지를 주고받는 것을 한눈에 알아보기 쉽게 표현할 수 있다.

게임 플레이 네트워킹

모든 역할을 서버에서 하기

과거에서 사용하던 기술이다.

클라이언트가 하는 역할은

  1. 사용자 입력(키 입력, 마우스 좌표)
  2. 화면 출력

서버에서 하는 일은

  1. 게임 로직 연산
  2. 화면 렌더링(그래픽 데이터 보유)
  3. 화면 송출(비디오 스트리밍)

이러한 방식은 온라인 게임에서 오래 전에 쓰던 방식이다. 텍스트 모드에서 터미널로 플레이하는 게임들이 이러한 방식을 사용한다.

하지만 과거와 달리 지금 게임은게임 그래픽 품질이 매우 높다. 게다가 게임 플레이를 하는 동안 화면은 1초에 30~60번 렌더링한다. 이러한 렌더링과 게임 로직을 모두 서버에서 하기는 무리다.

따라서 클라이언트-서버의 상호작용을 최적화해 주어야 한다.

렌더링은 클라이언트에서

  1. 서버는 월드의 전체 내용을 알고 있다. 서버는 이를 클라이언트에게 보낸다.
  2. 클라이언트는 상호작용을 메시지로 서버에 보낸다.
  3. 서버는 데이터를 처리하고 변화된 부분만 클라이언트에게 보낸다.
  4. 서버와 클라이언트는 동기화되어 같은 월드 상태를 가진다.

지속성 이벤트

월드의 상태에 영구적 변화를 가하는 것

단발성 이벤트

월드의 변화에 영향을 잠깐 주고 사라진다.
이는 지속성 이벤트로도 만들 수 있지만 미래가 클라이언트와 서버 사이에 서로 약속된 경우에는 단발성 이벤트가 효과적이다.

하지만 이러한 방법으로도 게임이 원활하게 작동하려면 서버와 클라이언트 사이에 레이턴시가 1/60초보다 훨씬 낮아야 한다. 게다가 레이턴시가 항상 균일해야 한다.
심지어 서버에 접속해 있는 플레이어의 개수가 많아질 수록 서버에서 해야 하는 일도 늘어난다.

따라서 1/60초마다 메시지를 보내는 대신에 1/10초마다 보낸다면 서버에 부담이 훨씬 적어질 것이다. 하지만 캐릭터의 움직임이 끊기는 문제가 있다.
이를 해결하는 방법이 상태 값 보정이다.

상태 값 보정

상태 값 보정은 클라이언트가 (플레이어 1은 위치가 4였는데 1/10초가 지난 후 5이다.)라는 메시지를 받았을 때, 곧바로 5를 보여주지 않고, 몇 프레임에 걸쳐서 4에서 5로 변화시키는 방법이다.

하지만 이러한 방법은 플레이어의 위치가 한 템포 늦게 표시되기 때문에 레이싱이나 FPS게임에서는 문제가 된다.

추측 항법

이쪽에서 저쪽 캐릭터의 위치 정보를 받았을 때 이미 지난 약간으ㅢ 시간만큼 예측하는 방법이다.
이러한 방법을 이용하려면 두 기기 간의 레이턴시를 알고 있어야 한다.
레이턴시를 구하는 방법으로는 라운드 트립 레이턴시가 있다.

레이턴시 마스킹

만약 아래와 같이 만든다면,

  1. 클라이언트에서 플레이어 캐릭터를 조종하는 명령을 서버에 보낸다.
  2. 서버에서는 플레이어 캐릭터의 이동 연산을 한다.
  3. 일정 시간마다 클라이언트에 이동 정보 메시지를 보낸다.
  4. 클라이언트는 이동 정보 메시지를 받으면 추측항법으로 캐릭터 위치를 부드럽게 만든 후 업데이트한다.

실제로 플레이 할 때 답답함을 느낀다.
이를 방지하는 방법 중 하나는 '사소한 것들은 클라이언트에서 판단하기'이며, 플레이어 자신이 조종하는 캐릭터의 위치 계산은 클라이언트에서 판단하고, 결과값만 서버에 보내는 것이다.

하지만, 해커가 플레이어의 이동 속도를 매우 빠르게 설정할 가능성도 있다.
따라서,

  1. 클라이언트는 플레이어 이동 정보를 서버에 보낸다.
  2. 서버는 이동 정보를 받아서 정상적인 값 범위에 있는지 검사한다.

혹은

  1. 클라이언트는 일단 이동하고, 이동 명령을 서버에게 보낸다.
  2. 서버는 명령 정보에 따라 플레이어를 이동시키고, 해당 위치 정보를 클라이언트에게 보낸다.
  3. 클라이언트는 서버에게서 메시지를 받으면 앞선 캐릭터의 위치를 무시하고 서버의 메시지에 따라 캐릭터를 이동시킨다.

두번째 방법이 해킹을 막는 데에는 가장 좋지만, 레이턴시가 높아지면 캐릭터 움직임이 손상된다.

또한, 일단 보여주고 처리하는 방법도 있다.
이는 행동 명령 메시지를 서버에 보내지만, 클라이언트에서는 행동을 연출하는 일부를 보여준다.
이후, 서버에서 메시지가 돌아오면 나머지 연출을 보여준다.

이러한 방법은 심리적으로 더 낫다. 클라이언트가 행동 명령을 내렸을 때, 바로 행동이 실행되는 것이 그나마 낫게 느껴진다.

넓은 월드, 많은 캐릭터 처리

게임 월드 안에 플레이어가 너무 많아지면, 통신량이 증가한다.
하지만 플레이어의 화면에서 보여지는 캐릭터의 수는 그 보다 훨씬 적으며, 이는 가시 영역 필터링으로 해결할 수 있다.

이를 위해서는

  1. 서버에서는 플레이어 각각에 대해서 각 플레이어가 볼 수 있는 캐릭터 목록을 갖고 있어야 한다.
  2. 캐릭터 각각에 대해서 자기 자신을 볼 수 있는 플레이어 목록 또한 가지고 있어야 한다.

서버에서는 이러한 정보를 갖고 있고 계속해서 업데이트 해야 한다. 하지만 서버에서 모든 플레이어에게 모든 캐릭터 정보를 보낼 때 보다는 처리량 부담 및 네트워킹 부담이 덜하다.

실시간 전략 시뮬레이션 게임에서 네트워크 동기화

전략 시뮬레이션 게임에서는 캐릭터 수가 수십 개에서 수백 개에 육박한다. 플레이어 수가 적음에도 불구하고 네트워크 동기화를 할 경우 통신량이 늘어난다. 이는 락스텝으로 해결할 수 있다.

락스텝 (스타크래프트)

군대에서 군인들이 발맞추어 나란히 걸어가는 모습을 의미한다.
락스텝은 컴퓨터 프로그램의 같은 상태에서 같은 입력을 주면 같은 결과가 나온다는 원리를 응용한 것으로,

  1. 각 플레리러는 다른 플레이어들에게 입력 명령을 보낸다.
  2. 플레이어의 입력 명령에 따라 모든 클라이언트가 동시에 씬 업데이트를 한다.

이는 각 클라이언트 플레이어의 입력 명령만 주고받으며, 캐릭터의 이동 상태를 주고받지 않는다. 입력 명령은 통신량이 그렇게 많지 않다.

만일 해커가 해킹한다 할지라도, 게임의 월드 상태에 대한 체크섬을 계산하여 상대와 비교한다

이러한 방법은 수많은 캐릭터를 조종해야 하는 게임이라 할지라도 정확한 움직임을 표현할 수 있다. 하지만 컴퓨터 간 레이턴시가 거의 없을 때에만 완벽하게 작동한다.

이를 해결하기 위해서는 입력 명령을 보내되, 언제 실행해야 하는지에 대한 미래시간까지 같이 보낸다.
미래시간이 너무 멀 경우 플레이어가 캐릭터에게 명령을 주고 그 명령을 실행하기까지 매우 오래 걸린다. 즉, 랙 현상을 체험한다.
반대로 너무 가까우면 게임 플레이 화면이 중간중간 멈춘다. 이는 캐릭터의 움직임이 중간중간 튀는 형태의 랙이 발생한다.

하지만 여전히 단점이 있다.

  1. 다른 플레이어가 플레이하고 있는 게임 중간에 확 들어오는 것을 만들기 어렵다.
  2. 게임 플레이에 관여하는 연산에 부동 소수점을 쓸 수 없다. 부동 소수점은 하드웨어 종류에 따라 미세하게 차이가 날 수 있는데, 이 차이가 누적되어 큰 차이로 이어질 수 있다.
  3. 플레이어 수가 많아지기 어렵다. 통신량이 증가하기 때문이다.
  4. 씬 업데이트가 일시 정지할 확률이 높다.
  5. 입력 명령의 속도에 민감한 게임에 부적합하다.필연적으로 캐릭터에게 넣은 행동은 미래 시간이 되어야 움직이기 때문이다.

실제 레이턴시 줄이기

레이턴시는 멀티플레이에 큰 영향을 준다. 가능하면 레이턴시를 줄여야 하는데, 이를 위한 방법으로는

TCP대신 UDP를 사용하여 패킷 유실 상황에서 패킷 재전송을 하는 시간을 줄인다. 하지만 데이터그램 유실은 피할 수 없다.

똑같은 양의 데이터를 보낸다 하더라도 가급적 적은 수의 패킷으로 보내는 것이 좋다. 예를 들어 1초에 메시지를 100개 이상 보낼 때는 뭉쳐서 보내는 것이 좋다.
하지만 너무 뭉치면 뭉치는 시간이 네트워크 지연처럼 느껴지므로, 10밀리초 이하가 적당하다.

클라이언트와 서버 간 통신과 클라이언트 간 통신을 섞어 쓰는 방법도 좋다. 전자는 C/S네트워킹, 후자는 P2P네트워킹이다.

게임 플레이 이외의 네트워킹

온라인 게임을 개발할 때는 컴퓨터 간에 어떤 대화가 오가는지 순서를 미리 정해두는 것이 좋다. 이는 시퀀스 다이어그램을 이용하면 쉽다.
더 자세하게 표현할 수 있는 액티비티 다이아그램을 이용하는 방법도 있다.

해킹과 보안

게임 사용자들이 해킹을 하는 유형은 크게 두 가지가 있다.

  1. 크래킹 : 게임 외 분야에서 흔히 이야기하는 해킹. 다른 사람의 ID와 비밀번호를 도용하거나 비밀 정보를 보는 것. 서버에 저장된 데이터를 훼손하거나 훔치는 것도 포함됨.
  2. 치트 혹은 조작 : 게임에서만 발견되는 형태의 해킹, 내 능력치를 비정상적으로 올리거나 다른 사람의 플레이를 망가뜨리는 것.

네트워크 해킹

로그인 할 때 데이터 교환을 도청하다가 ID와 비밀번호를 알아내는것, 따라서 ID와 비밀번호를 암호화 해서 보내야 한다.

많이 사용되는 암호화 알고리즘은 암호화 키를 이용하는 것이다.

평문 + 암호 키1-> 암호문
암호문 + 암호 키2-> 평문

암호 키 2는 서버에서만 갖고 있는 암호 키이다.
이는 비대칭 키 알고리즘이라 한다.

네트워크를 해킹하는 공격에는 DDOS공격도 있다. DDOS공격은 서버에 대량의 네트워크 데이터를 쏘는 것이다.

클라이언트 컴퓨터 해킹

해커가 많이 쓰는 방법은 클라이언트를 해킹하는 것, 다른 사람의 컴퓨터에 몰래 악성 프로그램을 심어 버리는 것이다.
사람들이 사용하는 운영체제나 응용 프로그램의 결함을 이용해서 악성 프로그램을 전파하기도 한다. 사용자가 안일하게 설정해 놓은 보안 설정을 역이용해서 뚫고 들어가기도 한다.

서버 컴퓨터 해킹

클라이언트와 마찬가지로 서버 쪽 운영 체제나 응용 프로그램 결함이나 보안 설정의 구멍을 이용하여 해킹한다. 특히 게임 서버가 해킹되면 모든 유저가 위험해지기 때문에 피해가 막심하다.

따라서 서버 고유의 역할인 웹 서버나 데이터베이스 서버에서는 클라이언트와는 다른 종류의 해킹을 추가로 예방해야 한다.

게임 서버에서는 일반적인 유저가 접속할 수 있는 리스닝 포트를 제외하고 모두 방화벽으로 막아 버려야 한다.

창과 방패의 싸움이다. 해커들은 더 다양한 공격 수단을 만들어 내고 이에 맞대응 하여 다양한 방어 수단을 갖춰야 한다.

게임 치트

네트워크 도청 및 조작을 해서 해킹을 하는 경우 서버에서 받는 메시지가 시간 차이도 유효한지 살펴야 한다.

또한 DDOS 공격과 유사하게 하여 다른 플레이어들을 랙 현상이 발생하게 만들 수 있으며, FPS등과 같은 게임에서 우위를 점할 수 있다.

클라이언트 내부 데이터를 조작하여 클라이언트에서 처리하는 승부 판정을 조작해 버릴 수 있다.

화면에는 표시되지 않더라도 다른 플레이어들의 정보가 클라이언트 메모리 안에 있다. 이것을 해킹하여 벽 뒤에 있는 플레이어들의 위치를 알 수 있다.

게임 컨트롤러를 조작하여 게임 화면에서 화상 인식을 한 후 자동으로 마우스를 조작해서 적 플레이어를 가리키게 해버릴 수 있다.

profile
코린이

0개의 댓글