IOS

[IOS] 웹소켓을 사용한 클라이언트 시간 동기화 방법과 문제점

웹소켓 채팅을 기반으로 실시간 게임을 만들기 위해 했던 시도와 그 과정에서의 생각을 정리한 글이다.

구현하려고 했던 게임의 핵심 기능은 소켓 서버와 연결된 다수의 플레이어들이 자신의 차례에 주어지는 일정 시간동안 특정 메시지를 입력하는 것이었다. 문제는 모든 플레이어들이 동시에 게임을 시작하고 동시에 플레이어들의 차례를 바꿔야했다. 즉, 게임이 진행되는 동안 모든 클라이언트가 동일한 시간을 공유하게 만드는 것이 관건이었다.


서론

기본적으로 게임시작 전, 각 플레이어들이 준비 상태를 서버에 알리면 모든 플레이어의 준비가 끝난 것을 확인한 서버는 게임시작 이벤트를 클라이언트에 보내고 이벤트를 수신한 각 클라이언트는 게임이 진행되는 화면으로 뷰를 전환시키는 과정이 이뤄진다.

 

 

본론

1. 게임 화면으로 전환이 완료됐을때 클라이언트 타이머 발동

더보기

각 클라이언트에 일정한 시간동안 동작하는 타이머를 설정하고 게임화면 로딩이 끝나면 그 타이머를 발동시켜 그때부터 시간이 경과되게 하는 방법을 시도했다. 하지만 서버가 모든 클라이언트에게 동시에 이벤트를 보내더라도 이벤트가 도착하는 시간이 클라이언트마다 다를 수 있고 기기의 퍼포먼스적인 이슈때문에 뷰의 로딩이 늦어져 타이머가 늦게 발동될 수 있다는 문제가 있었다.

 

2. 서버에서 클라이언트 타이머 발동시간 지정

더보기

각 클라이언트의 로딩 및 응답 시간을 고려한 미래의 타임 스탬프를 UTC 형식으로 전송하여 각 클라이언트가 해당 타임 스탬프에 도달했을때 타이머를 발동하게 만들었다. 이 방법은 1번의 단점을 보완할 수 있었지만, 만약 클라이언트 기기의 시스템에 설정된 시간과 서버의 시간이 조금이라도 다를 경우 타임 스탬프까지 남은 시간을 다르게 계산할 수 있다는 문제가 존재했다.

 

3. 서버 시간을 사용해 클라이언트 타이머 발동시간 계산

더보기

클라이언트와 서버의 시간이 달라 발생하는 2번 방법의 문제를 해결하기 위해 클라이언트의 시간을 사용하지 않고 오직 서버에서 보내주는 타임 스탬프만을 사용한다. 화면 로딩이 끝나 서버로부터 타임 스탬프를 받은 클라이언트는 이후에 추가로 미래 시간을 나타내는 타임 스탬프를 받아 두 타임 스탬프 사이의 시간 간격을 계산하여 그 간격 만큼 시간이 경과된 후 타이머를 발동하게 만들었다. 1번, 2번 방법의 문제를 해결했지만 궁극적으로 클라이언트에 타이머를 설정하는 방법은 앱이 백그라운드로 전환됐을때 타이머가 동작하지 않는 문제가 있어 다른 방법을 찾아야했다.

 

4. 서버 타이머로 시간 동기화

모든 클라이언트의 화면 로딩이 완료된 것을 확인한 서버는 일정한 시간동안 클라이언트에 주기적으로 시간 이벤트를 보내 모든 클라이언트가 같은 시간으로 업데이트되도록 만들었다. 만약 기기 문제로 앱이 잠시 멈추거나 백그라운드로 전환되어도 다시 서버와 연결된 직후 곧바로 이벤트를 받아서 앱이 멈춰있었던 시간만큼 경과된 시간으로 갱신하여 다른 클라이언트와 동일한 시간을 가질 수 있었다.

 

결론

게임이 진행되는 동안 시간이 지날때마다 남은 시간을 지속적으로 클라이언트에 보내줌으로써 클라이언트의 시간을 동기화할 수 있었다.


참고 링크

https://gamedev.stackexchange.com/questions/55508/start-timer-in-two-clients-the-same-time

 

Start timer in two clients the same time

I want to create a client/server turned-based game where each player will have 5 seconds in order to play. If extends this time will be other player's turn to play. In order to do this, I have crea...

gamedev.stackexchange.com

https://stackoverflow.com/questions/14007976/how-can-i-sync-two-javascript-timers-via-websockets

 

How can I sync two javascript timers via websockets

I have a site with a js visual metronome (like a conductor) that can be triggered via a websocket on multiple machines. How can I make the start of the metronomes as sync as possible? Thanks.

stackoverflow.com

https://stackoverflow.com/questions/14964318/how-can-i-get-the-actual-date-and-time-if-the-device-date-and-time-are-inaccurat

 

How can I get the actual date and time if the device date and time are inaccurate?

I noticed that if I set my device time manually, and turn off the automatic time sync on my iOS device, [NSDate date] returns the date and time assuming the device time is correct--which it may not...

stackoverflow.com

https://developer.apple.com/forums/thread/110044

 

Is there any way to get actual cur… | Apple Developer Forums

What’s your high-level goal here? KMT et al are correct in that getting a timestamp from a trusted server is the only guaranteed solution to this problem. If that doesn’t work for you then there may be other paths you can take, but this depends on your

developer.apple.com

https://devdreamz.com/question/795161-nstimer-fires-before-the-firedate

 

NSTimer fires before the firedate - DevDreamz

As explained in a couple of places (here is a good example), NSTimer's fireDate isn't actually a calendar datetime at which the timer fires. It's more accurate to thi...

devdreamz.com