반응형
서버 시간을 가져와야하는 이유
대부분의 프로그램(앱)에서는 클라이언트와 서버 간의 통신이 존재합니다. 하지만 클라이언트에서 사용하는 시간이 있고, 서버에서 사용하는 시간이 따로 존재하며 이 둘은 서로 동기화가 필요합니다. 클라이언트에서 단순하게 'DateTime.Now' 사용한다면 이는 기기 시간 변경만으로도 에러 및 프로그램 내부적인 스케줄링에 치명적으로 영향을 줄 수 있습니다.
프로그램 시간 제약 조건
제가 생각하는 제약 조건은 아래와 같습니다.
- DateTime.Now와 같은 IDE에서 제공하는 기기 시간을 가져오는 코드 사용은 지양한다. 이는 클라이언트에 영향을 끼칠 수 있습니다.
- DateTime.Now 대신 사용할 시간을 따로 관리하는 로직을 구상하여 사용한다. 기기 시간을 조작해도 영향을 끼치지 않는 아키텍쳐가 필요합니다.
- 기기 시간은 서버에서 주기적으로 가져와 갱신을 합니다.
적용 방법
- 웹 통신의 경우, Headers 중 "Date" 헤더를 가져와서 읽습니다. HTTP 헤더 계층 구조에서 기본적으로 시간을 포함하여 통신을 하기에 기본적으로 송신자의 시간, 즉 서버 시간을 알 수가 있습니다.
- 웹 통신의 방식이 아닌 경우, 서버에서 시간 관련된 패킷을 보내어 적용해줍니다. 이 방식은 보통의 방식이 아닌 통신 모듈이 따로 명시되어있는 프로젝트에 한합니다. (TCP 또는 UDP)
스크립트
예시로 적용 방법의 1번 방법으로 웹 통신에서 시간을 가져와 적용하는 방법입니다.
using System;
using System.Net;
using System.Threading.Tasks;
public static class Time
{
/// <summary>
/// 클라이언트와 동기화된 시간 차이 (Tick)
/// </summary>
private static long diffTick = 0L;
/// <summary>
/// 기준 시간
/// </summary>
private static DateTime syncTime = DateTime.Now;
/// <summary>
/// 현재 시간
/// </summary>
public static DateTime NowTime => DateTime.Now.AddTicks(diffTick);
/// <summary>
/// UTC 시간 (KST + 9시간)
/// </summary>
public static DateTime UtcNowTime => NowTime.AddHours(9f);
/// <summary>
/// 동기화 시간 업데이트
/// </summary>
/// <param name="dateStr"></param>
public static void UpdateDateTime(string dateStr)
{
if (DateTime.TryParse(dateStr, out DateTime dateTime))
{
syncTime = dateTime;
diffTick = (syncTime - DateTime.Now).Ticks;
}
}
/// <summary>
/// 서버 동기화
/// </summary>
/// <param name="serverURL"></param>
public static async Task Synchronization(string serverURL)
{
WebRequest request = WebRequest.Create(serverURL);
WebResponse response = await request.GetResponseAsync();
if (Array.Exists(response.Headers.AllKeys, headerKey => headerKey.Equals("Date")))
UpdateDateTime(response.Headers["Date"]);
}
}
예제
private static bool isCheckIn = false;
static void Main(string[] args)
{
CheckServerTime();
while (!isCheckIn)
{
Thread.Sleep(100);
}
}
private static async void CheckServerTime()
{
string url = "https://moondongjun.tistory.com//";
// 서버와 클라이언트 시간 동기화
await Time.Synchronization(url);
// 서버 기준으로 만들어진 시간으로 사용할 수 있다.
Console.WriteLine($"'{url}'의서버 시간 : {Time.NowTime}"); // DateTime.Now (x)
isCheckIn = true;
}
서버와 클라이언트간 시간을 동기화하여 보다 밀도 높은 정확도로 현재 시간을 사용할 수 있습니다. 예제 코드에는 없지만, Time.UpdateDateTime()를 통하여 시간을 기준 시간을 조정할 수 있습니다. 이 함수를 통하여, 주기적으로 시간을 받아오는 것이 좋겠습니다. PC의 성능은 모두 제각각이기에 주기적으로 동기화를 해주지 않는다면, 결국 서버와 클라이언트 사이에는 시간이 미세하게 점점 더 격차가 생길 수 있습니다.
마무리
개인 프로젝트로 웹 통신을 사용하는 중인데, 기기 시간 조작에 걱정이 되어 알아보던 중, 헤더 계층 구조에 시간이 존재한다는 것을 알고 사용하게 되었습니다. 장기간 켜두는 과정에서 시간 오차가 생기는 이슈가 있었는데, 주기적으로 웹 통신하는 과정 중, 시간을 계속 갱신하여 이상 없이 적용 중입니다.😁
반응형
'R&D' 카테고리의 다른 글
Unity, 매쉬 변형 예제 (0) | 2024.01.23 |
---|---|
Unity, 유니티 버전 업그레이드 이후 전체 파일 및 에셋 갱신하기 (Refresh) (0) | 2022.12.22 |
Unity, 전역으로 코루틴 사용하기(Static Coroutine) (0) | 2022.07.24 |
NGUI Atlas 화질 저하 해결 방법 (0) | 2022.04.23 |
Unity, UI Masking 중첩 해결 방안 (0) | 2022.03.06 |
댓글