본문 바로가기
Study

프로그램의 정확 시간 측정이 어려운 이유와 해결 방법 제시

by Client. DJ 2022. 8. 16.
반응형

서버로부터 시간을 받아온다. NTP 개념도

예시

아래와 같이 OS 시간 조작 방지를 위해, 커스텀 타이머 클래스를 제작하였다고 가정합시다.

using System;
using System.Threading.Tasks;

/// <summary>
/// 프로그램 커스텀 타이머
/// </summary>
public static class MyTimer
{
    static DateTime startTime;
    static long millisecond = 0L;

    public static void Start()
    {
        startTime = DateTime.Now;
        TimeUpdater();
    }

    private static async void TimeUpdater()
    {
        while (true)
        {
            await Task.Delay(1);
            ++millisecond;
        }
    }

    public static DateTime NowTime => startTime.AddMilliseconds(millisecond);
}

아래와 같이 12시간 뒤의 시간을 OS 시간과 비교를 해보면 과연 똑같이 나올까요?

private static void Main(params string[] args)
{
    MyTimer.Start();
    Thread.Sleep(1000 * 60 * 60 * 12)	// 12시간 딜레이
    
    // OS 타이머의 현재 시간
    Console.WriteLine(DateTime.Now);
    
    // 직접 작성한 프로그램 타이머 현재 시간
    Console.WriteLine(MyTimer.NowTime);
}

예시 결과

서로 다른 시간의 오차 발생

순수하게 '컴퓨터 1대'로만 정확한 시간을 구할 수 있는가?

자체적으로 타이머 프로그램을 만든다고 하면 간단하게 만들 수 있습니다. 다만, 장시간에서 사용할 시 원래 PC에서 사용하는 시간과도 괴리가 생기기 시작합니다. 더욱 더 긴 시간을 진행하는 경우, 정밀도에서 차이가 발생할 수 있습니다.

왜 괴리가 발생할까?

아래와 같은 이유가 있습니다.

  1. CUP 마다 각기 속도가 다를 수 있다. 모든 PC는 성능이 다르기에 같은 프로그램을 사용하더라도 속도가 각기 다르게 나온다. 이는 하드웨어의 노후화도 포함이 된다.
  2. 워커쓰레드(또는 멀티쓰레드)를 사용하여 일정 간격(Thread.Sleep)으로 타이밍을 요청한다. 1)에서의 이유와 비슷하며, Thread.Sleep은 쓰레드를 그만큼 잠깐 점유권 놓아주는 유휴 시간이지 정확하게 우리가 '입력한 값' 시간 뒤에 돌아온다는 보장이 없다. 유후 시간 이후 다시 점유권을 획득하는 과정에서도 약 10ms~20ms까지 발생한다. 또한 간단한 연산에도 소요되는 시간이 존재한다. 결과적으로 '유휴 시간 + 점유 획득 시간 + 연산 시간'이라는 반복적인 연산에서 괴리가 발생하게 된다.
  3. 소수점의 계산을 하는 경우, 부동소수점의 이탈로 값의 변형이 생긴다. Tick의 개념으로 long같은 정수형 변수로 사용한 뒤 변환하여 사용하는 것이 좋다.
  4. 서버 시간을 요청하고, 받아오고 하는 이 두 가지의 과정에서 패킷이 도착하는 시간이 딜레이 될 수 있다.
  5. 프로그래밍 언어별로 지원하는 타이머 함수 또는 현재 시간을 찍어주는 함수에 따라 이슈가 있을 수 있다. (대표적으로  자바스크립트 setTimeout()은 호출할 때마다 1~5ms 오차가 발생한다. 간단하게 반복 호출하면 바로 확인 가능하다.)

해결 방법

시간의 정밀도를 높히고 싶다면, 주기적으로 다시 조정을 해주면됩니다.

  • 대부분의 프로그램들은 주기적으로 서버와 동기화를 시도한다.

다시 돌아와서 순수하게 컴퓨터 1대로만으로는 정확한 시간을 가져올 수 없습니다. 이렇게하면 어느 정도 완화되어 서버와 시간이 동기화됩니다. 이는 우리가 주로 사용하는 OS들에서도 찾아볼 수도 있습니다.

Window OS에서도 시간을 동기화할 서버를 입력할 수 있다.

서버 시간 제공 사이트 (NTP)

NTP는 Network Time Protocol의 약자이며, 서버와 클라이언트(PC) 사이 시간을 동기화하기 위한 규약 또는 규격을 뜻합니다. 대표적으로 NTP를 제공하는 사이트는 아래와 같습니다.

time.bora.net LG유플러스
time.nuri.net 아이네트호스팅
ntp.kornet.net KT
time.kriss.re.kr 한국표준과학연구원(KRISS)
time.nist.gov NIST
time.windows.com 마이크로소프트
time.nist.gov NIST
time.google.com 구글
ntp2.kornet.net KT

서버 시간 가져오기 예제

하지만, 우리가 이용하는 서버가 있다면, 위의 주소로 이용하시면 안됩니다. HTTP의 헤더 계층 구조에는 "Date" 헤더가 있으며 이는 시간을 읽어올 수 있습니다.

HTTP의 'Date' Header

마무리

생각보다 '완벽'한 것은 없습니다. 완벽하게 보이려고 여러가지의 보조적인 장치와 기능들이 숨어있을뿐. 생활 속에서도 쉽게 찾아볼 수 있습니다. 가끔 아날로그 시계가 시간이 안 맞아서 재조정한 적 없으신가요?


참고: https://zetawiki.com/wiki/%EA%B3%B5%EC%9A%A9_NTP_%EC%84%9C%EB%B2%84_%EB%AA%A9%EB%A1%9D

참고: https://docs.microsoft.com/ko-kr/windows-server/networking/windows-time-service/support-boundary

반응형

댓글