본문 바로가기

TechLog

sntp를 이용해서 시스템 시간 자동으로 설정하기

sntp 이용해서 시스템 시간 자동으로 설정하기

특 정 장소에 설치되어 오랫동안 동작해야 하는 컴퓨터의 경우, 시스템의 시간이 자동으로 정확한 시간으로 재설정되어야 하는 상황이 생깁니다. 이럴 경우 컴퓨터가 네트웍에 연결되어 있으면 sntp 서비스와 윈도우의 Windows Time 서비스를 활용해 컴퓨터를 정확한 시간으로 설정할 수 있습니다.

 

 

안녕하세요 : )

 

일단 이 아티클은 Windows 2003, XP에서 테스트된 것임을 미리 알려드립니다. 현재 Kenial에게 테스트해볼 Windows 2000 시스템이 없어서 그런 것이니 양해를 바랍니다.

 

닷 넷 프레임워크에서 시스템 시간을 설정하려면 WinAPI를 사용하는 방법 밖에 없길래, 다른 방법을 강구해 보다가 나온 해결책입니다. 시스템의 Windows Time 서비스와 sntp 타임 서버를 이용해 프로그램이 실행될 때마다 시스템 시간을 갱신하는 코드를 작성해 보겠습니다.

 

그럼 시작합니다.

 

 

시스템의 시간을 정확하게 유지하라

 

키오스크 및 안내 용도의 시스템이 공공장소 등에 설치되어 있는 경우, 그 특성상 상당히 오랜 시간을 관리자의 개입 없이 동작해야 할 경우가 있다. 그런데 만약 여기서 구동되는 프로그램이 시간과 관계된 프로그램이라면?

 

컴 퓨터를 조립해보며 메인보드를 이것 저것 사용해 본 경험이 있는 유저라면 알겠지만, cmos에서 유지되는 시스템 시간은 '아주 정확한' 수준의 정밀도를 제공하지 못한다. 메인보드 특성에 따라 달라지기는 하지만 하루에 몇 초 정도가 왔다갔다하는 경우가 보통이고, 심한 경우는 아예 시스템 시간이 리셋되는 경우마저 있다. (물론 이런 메인보드를 공공장소용 시스템에 공급했다가는 난리가 날 것이다)

 

물론 sntp 서버를 사용한다고 해도 그 시간이 ms 단위까지 정확하기는 힘들다. 하지만 어차피 네트워크에 연결되는 시스템의 특성상 그것까지 반영하기는 힘들다고 가정하고, 코드를 설명하도록 하겠다.

 

 

실제 코드

 

작업 과정은 다음과 같다 :

  1. (만약 중지되어 있다면) Windows Time 서비스를 시작한다.

  2. 시간을 동기화 할 sntp 서버를 지정한다.

  3. 시간을 동기화한다.

 

아주 간단하다 : )

윈도우의 cmd 쉘에서 실제 입력되는 명령은 다음과 같다 :

 

net start w32time

net time /setsntp:time.nuri.net

w32tm /resync

 

Kenial time.nuri.net sntp 서버를 사용하고 있으나, 추가적인 주소가 필요하다면 구글 등에서 sntp server list 등을 검색해보면 몇 개의 주소를 더 얻을 수 있을 것이다.

 

그렇다면 C#에서의 코드를 작성해 보자 :

 

private void SyncLocalTime()

{

    System.Diagnostics.ProcessStartInfo startinfo = new System.Diagnostics.ProcessStartInfo();

    System.Diagnostics.Process process;

    // 화면에 cmd 윈도우를 보여주지 않기 위해 필요한 코드

    startinfo.UseShellExecute = false;

    startinfo.CreateNoWindow = true;

 

    // 실행할 커맨드와 인자를 적는다

    startinfo.FileName = "net";

    startinfo.Arguments = "start w32time";

    // 실행

    process = System.Diagnostics.Process.Start(startinfo);

    // 프로세스가 종료될 까지 대기

    process.WaitForExit();

    process.Close();

 

    startinfo.FileName = "net";

    startinfo.Arguments = "time /setsntp:time.nuri.net";

    process = System.Diagnostics.Process.Start(startinfo);

    process.WaitForExit();

    process.Close();

 

    startinfo.FileName = "w32tm";

    startinfo.Arguments = "/resync";

    process = System.Diagnostics.Process.Start(startinfo);

    process.WaitForExit();

    process.Close();

}

 

위와 같은 코드를 작성하고 Form_Load 등의 함수에 넣어주면 프로그램이 시작될 때 마다 시간을 동기화하게 된다.

 

 

추가 사항

 

위와 같은 코드를 사용하면 일단 잘 동작하는 것 같다. 하지만 시스템 시간을 한 달 정도 빠르거나 늦게 해 놓고 w32tm /resync를 실행해 보자. 다음과 같은 에러 메시지를 만날 수 있다 :

 

 

 

 

C:\Documents and Settings\Administrator>w32tm /resync

동기화 명령 전송 - local computer...

필요한 시간 변경이 너무 커 컴퓨터가 동기화되지 않았습니다.

 

 

 

 

. 이러한 동작은 Windows Time 서비스에서 의도된 것으로, 현재 시스템의 시간과 sntp 서버 사이의 시간 차이가 너무 크면 시간 설정을 하지 않도록 기본 설정이 되어 있는 것이다. Windows Time 서비스의 설정을 변경하여 그 기본값을 바꿀 수 있다.

 

레지스트리 HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Config 위치에 있는 MaxPosPhaseCorrection, MaxNegPhaseCorrection 항목이 각각 시간 차이에 대한 상한/하한 값이다. 기본값은 54000 (=15시간, 초단위)로 되어 있으나, 이를 -1로 설정하고 Windows Time 서비스를 재시작하면 시간 차이에 관계없이 동기화가 이루어지게 된다.

 

첨부한 레지스트리 파일을 참고하기 바란다.

 

 

정리

 

Kenial 이 하는 일이 키오스크 제작과 관련된 일이다보니, 하는 일에 관련된 아티클만 줄창 올리게 되네요. 시간 동기화 같은 기능은 사실 자주 쓰이는 기능은 아닙니다만, 시간과 관련된 프로그램에서는 쓰이는 경우가 꽤 많으므로 '이렇게도 구현할 수 있구나..' 정도로 알고 계시면 좋을 듯 합니다.

 

그럼 : )