早知道拿去買便當了,有點傷本Orz
這一個月我要讓時間同步的方法有以下幾種:
- 進去BIOS設定
- 在開機時透過時鐘同步的更能實現
今天睡醒時,
就直接寫一個Service在開機時透過網路與NTP Server取得時間並設定在系統上
首先開啟一個專案,選擇Windows服務
在Service1的設計畫面點右鍵/加入安裝程式
ProjectInstaller設計畫面去設定serviceInstaller1屬性
DelayedAutoStart屬性設定為true,使得在開機時延遲自動執行,延遲是怕剛開機時沒有網路服務,所以特別讓他能等待一會後在開始同步進行更新
StartType:設定為Automatic,讓開機時自動執行
接著設定serviceProcessInstaller1的屬性
將Account選為LocalSystem
將EventLog的元件拖曳到Service1的設計畫面上
並複製以下程式碼貼到Service1.cs和NTPClient.cs
不要按下F6(Run Project)會有錯誤,請按下按下F6(Build Project) VS會對專案進行建置
Service1.cs:
using System.ServiceProcess;
using System.Threading;
namespace MyUpdateTimeService
{
public partial class MyUpdateService : ServiceBase
{
private NTPClient ntpClient;
const string source = "UpdateTimeService";
public MyUpdateService()
{
InitializeComponent();
this.AutoLog = false;
if (!System.Diagnostics.EventLog.SourceExists(source))
{
System.Diagnostics.EventLog.CreateEventSource(source, "UpdateTimeLog");
}
eventLog1.Source = source;
ntpClient = new NTPClient();
}
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("Start");
bool isSet = ntpClient.GetNtpTime();
if (isSet)
{
eventLog1.WriteEntry("true");
this.OnPause();
}
else
eventLog1.WriteEntry("false");
Thread.Sleep(1000);
}
protected override void OnStop()
{
eventLog1.WriteEntry("Stop");
}
}
}
NTPClient.cs:
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace MyUpdateTimeService
{
public class NTPClient
{
protected internal bool GetNtpTime()
{
const string ntpServer = "time.nist.gov";
byte[] ntpData = new byte[48];
//LeapIndicator = 0 (no warning), VersionNum = 3 (IPv4 only), Mode = 3 (Client Mode)
ntpData[0] = 0x1B;
IPAddress[] addresses = Dns.GetHostEntry(ntpServer).AddressList;
IPEndPoint ipEndPoint = new IPEndPoint(addresses[0], 123);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Connect(ipEndPoint);
socket.Send(ntpData);
socket.Receive(ntpData);
socket.Close();
const byte serverReplyTime = 40;
//Get the seconds part
ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
//Get the seconds fraction
ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
//Convert From big-endian to little-endian
intPart = SwapEndianness(intPart);
fractPart = SwapEndianness(fractPart);
var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
//UTC time + 8
DateTime networkDateTime = (new DateTime(1900, 1, 1))
.AddMilliseconds((long)milliseconds).AddHours(8);
if (UpdateTime.SetTime(networkDateTime))
return true;
return false;
}
// stackoverflow.com/a/3294698/162671
static uint SwapEndianness(ulong x)
{
return (uint)(((x & 0x000000ff) << 24) +
((x & 0x0000ff00) << 8) +
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24));
}
public class UpdateTime
{
[DllImport("kernel32.dll")]
private static extern bool SetLocalTime(ref TIME time);
[StructLayout(LayoutKind.Sequential)]
private struct TIME
{
public short year;
public short month;
public short dayOfWeek;
public short day;
public short hour;
public short minute;
public short second;
public short milliseconds;
}
protected internal static bool SetTime(DateTime dt)
{
TIME time;
time.year = (short)dt.Year;
time.month = (short)dt.Month;
time.dayOfWeek = (short)dt.DayOfWeek;
time.day = (short)dt.Day;
time.hour = (short)(dt.Hour);
time.minute = (short)dt.Minute;
time.second = (short)dt.Second;
time.milliseconds = (short)dt.Millisecond;
return SetLocalTime(ref time);
}
}
}
}
接著用管理者權限開啟終端機,不用沒辦法將服務安裝上去
並切換到專案的Release資料夾底下輸入指令
#安裝服務 installutil 服務名稱.exe #移除服務 installutil /u 服務名稱.exe
安裝成功的畫面如下:
解除安裝的畫面如下:
安裝完成後,可以在『控制台/系統及安全性/系統管理工具/服務』看到剛剛安裝上去的Service
如果想查看執行Log,可以在『控制台/系統及安全性/系統管理工具/事件檢視器/Windows紀錄/硬應用程式』看到
現在可以選擇要手動將該服務開啟,或是重開機自動會執行該服務
寫完程式以及文章整個好餓XD
參考資料:
http://stackoverflow.com/questions/1193955/how-to-query-an-ntp-server-using-c
http://pastebin.com/KrDSTz4J
http://msdn.microsoft.com/zh-tw/library/ms172517(v=vs.90).aspx
http://j796160836.pixnet.net/blog/post/40306051
http://www.dotblogs.com.tw/kirkchen/archive/2010/04/30/14943.aspx











