早知道拿去買便當了,有點傷本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