如何查询使用C#的NTP服务器?

我所需要的是一种使用C#查询NTP服务器的方法,以便将NTP服务器的date时间作为stringDateTime

这最简单的forms怎么可能?

由于旧的接受的答案被删除(这是一个谷歌代码搜索结果,不再存在的链接),我想我可以回答这个问题,以供将来参考:

 public static DateTime GetNetworkTime() { //default Windows time server const string ntpserver = "time.windows.com"; // NTP message size - 16 bytes of the digest (RFC 2030) var ntpData = new byte[48]; //Setting the Leap Indicator, Version Number and Mode values ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode) var addresses = Dns.GetHostEntry(ntpserver).AddressList; //The UDP port number assigned to NTP is 123 var ipEndPoint = new IPEndPoint(addresses[0], 123); //NTP uses UDP using(var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { socket.Connect(ipEndPoint); //Stops code hang if NTP is blocked socket.ReceiveTimeout = 3000; socket.Send(ntpData); socket.Receive(ntpData); socket.Close(); } //Offset to get to the "Transmit Timestamp" field (time at which the reply //departed the server for the client, in 64-bit timestamp format." 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 var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds); return networkDateTime.ToLocalTime(); } // stackoverflow.com/a/3294698/162671 static uint SwapEndianness(ulong x) { return (uint) (((x & 0x000000ff) << 24) + ((x & 0x0000ff00) << 8) + ((x & 0x00ff0000) >> 8) + ((x & 0xff000000) >> 24)); } 

注意:您将不得不添加以下命名空间

 using System.Net; using System.Net.Sockets; 

这是该函数的一个优化版本,它可以消除对BitConverter函数的依赖,并使其与.NETMF(.NET Micro Framework)兼容。

 public static DateTime GetNetworkTime() { const string ntpserver = "pool.ntp.org"; var ntpData = new byte[48]; ntpData[0] = 0x1B; //LeapIndicator = 0 (no warning), VersionNum = 3 (IPv4 only), Mode = 3 (Client Mode) var addresses = Dns.GetHostEntry(ntpserver).AddressList; var ipEndPoint = new IPEndPoint(addresses[0], 123); var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); socket.Connect(ipEndPoint); socket.Send(ntpData); socket.Receive(ntpData); socket.Close(); ulong intPart = (ulong)ntpData[40] << 24 | (ulong)ntpData[41] << 16 | (ulong)ntpData[42] << 8 | (ulong)ntpData[43]; ulong fractPart = (ulong)ntpData[44] << 24 | (ulong)ntpData[45] << 16 | (ulong)ntpData[46] << 8 | (ulong)ntpData[47]; var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L); var networkDateTime = (new DateTime(1900, 1, 1)).AddMilliseconds((long)milliseconds); return networkDateTime; } 

CodePlex中的.NET Micro Framework工具包有一个NTPClient 。 我从来没有用过它,但看起来不错。

这里还有另外一个例子。

我知道这个话题已经很老了,但是这样的工具总是很方便。 我已经使用了上面的资源,并创建了一个NtpClient版本,允许异步获取准确的时间,而不是基于事件。

  /// <summary> /// Represents a client which can obtain accurate time via NTP protocol. /// </summary> public class NtpClient { private readonly TaskCompletionSource<DateTime> _resultCompletionSource; /// <summary> /// Creates a new instance of <see cref="NtpClient"/> class. /// </summary> public NtpClient() { _resultCompletionSource = new TaskCompletionSource<DateTime>(); } /// <summary> /// Gets accurate time using the NTP protocol with default timeout of 45 seconds. /// </summary> /// <returns>Network accurate <see cref="DateTime"/> value.</returns> public async Task<DateTime> GetNetworkTimeAsync() { return await GetNetworkTimeAsync(TimeSpan.FromSeconds(45)); } /// <summary> /// Gets accurate time using the NTP protocol with default timeout of 45 seconds. /// </summary> /// <param name="timeoutMs">Operation timeout in milliseconds.</param> /// <returns>Network accurate <see cref="DateTime"/> value.</returns> public async Task<DateTime> GetNetworkTimeAsync(int timeoutMs) { return await GetNetworkTimeAsync(TimeSpan.FromMilliseconds(timeoutMs)); } /// <summary> /// Gets accurate time using the NTP protocol with default timeout of 45 seconds. /// </summary> /// <param name="timeout">Operation timeout.</param> /// <returns>Network accurate <see cref="DateTime"/> value.</returns> public async Task<DateTime> GetNetworkTimeAsync(TimeSpan timeout) { using (var socket = new DatagramSocket()) using (var ct = new CancellationTokenSource(timeout)) { ct.Token.Register(() => _resultCompletionSource.TrySetCanceled()); socket.MessageReceived += OnSocketMessageReceived; //The UDP port number assigned to NTP is 123 await socket.ConnectAsync(new HostName("pool.ntp.org"), "123"); using (var writer = new DataWriter(socket.OutputStream)) { // NTP message size is 16 bytes of the digest (RFC 2030) var ntpBuffer = new byte[48]; // Setting the Leap Indicator, // Version Number and Mode values // LI = 0 (no warning) // VN = 3 (IPv4 only) // Mode = 3 (Client Mode) ntpBuffer[0] = 0x1B; writer.WriteBytes(ntpBuffer); await writer.StoreAsync(); var result = await _resultCompletionSource.Task; return result; } } } private void OnSocketMessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args) { try { using (var reader = args.GetDataReader()) { byte[] response = new byte[48]; reader.ReadBytes(response); _resultCompletionSource.TrySetResult(ParseNetworkTime(response)); } } catch (Exception ex) { _resultCompletionSource.TrySetException(ex); } } private static DateTime ParseNetworkTime(byte[] rawData) { //Offset to get to the "Transmit Timestamp" field (time at which the reply //departed the server for the client, in 64-bit timestamp format." const byte serverReplyTime = 40; //Get the seconds part ulong intPart = BitConverter.ToUInt32(rawData, serverReplyTime); //Get the seconds fraction ulong fractPart = BitConverter.ToUInt32(rawData, serverReplyTime + 4); //Convert From big-endian to little-endian intPart = SwapEndianness(intPart); fractPart = SwapEndianness(fractPart); var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L); //**UTC** time DateTime networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds); return networkDateTime; } // stackoverflow.com/a/3294698/162671 private static uint SwapEndianness(ulong x) { return (uint)(((x & 0x000000ff) << 24) + ((x & 0x0000ff00) << 8) + ((x & 0x00ff0000) >> 8) + ((x & 0xff000000) >> 24)); } } 

用法:

 var ntp = new NtpClient(); var accurateTime = await ntp.GetNetworkTimeAsync(TimeSpan.FromSeconds(10)); 

一个修改版本来补偿网络时间和计算与DateTime-Ticks(比毫秒更精确)

 public static DateTime GetNetworkTime() { const string Ntpserver = "pool.ntp.org"; const int DaysTo1900 = 1900 * 365 + 95; // 95 = offset for leap-years etc. const long TicksPerSecond = 10000000L; const long TicksPerDay = 24 * 60 * 60 * TicksPerSecond; const long TicksTo1900 = DaysTo1900 * TicksPerDay; var ntpData = new byte[48]; ntpData[0] = 0x1B; // LeapIndicator = 0 (no warning), VersionNum = 3 (IPv4 only), Mode = 3 (Client Mode) var addresses = Dns.GetHostEntry(Ntpserver).AddressList; var ipEndPoint = new IPEndPoint(addresses[0], 123); long pingDuration = Stopwatch.GetTimestamp(); // temp access (JIT-Compiler need some time at first call) using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { socket.Connect(ipEndPoint); socket.ReceiveTimeout = 5000; socket.Send(ntpData); pingDuration = Stopwatch.GetTimestamp(); // after Send-Method to reduce WinSocket API-Call time socket.Receive(ntpData); pingDuration = Stopwatch.GetTimestamp() - pingDuration; } long pingTicks = pingDuration * TicksPerSecond / Stopwatch.Frequency; // optional: display response-time // Console.WriteLine("{0:N2} ms", new TimeSpan(pingTicks).TotalMilliseconds); long intPart = (long)ntpData[40] << 24 | (long)ntpData[41] << 16 | (long)ntpData[42] << 8 | ntpData[43]; long fractPart = (long)ntpData[44] << 24 | (long)ntpData[45] << 16 | (long)ntpData[46] << 8 | ntpData[47]; long netTicks = intPart * TicksPerSecond + (fractPart * TicksPerSecond >> 32); var networkDateTime = new DateTime(TicksTo1900 + netTicks + pingTicks / 2); return networkDateTime.ToLocalTime(); // without ToLocalTime() = faster } 

http://www.codeproject.com/Articles/237501/Windows-Phone-NTP-Client将会为Windows Phone工作。

添加相关的代码

 /// <summary> /// Class for acquiring time via Ntp. Useful for applications in which correct world time must be used and the /// clock on the device isn't "trusted." /// </summary> public class NtpClient { /// <summary> /// Contains the time returned from the Ntp request /// </summary> public class TimeReceivedEventArgs : EventArgs { public DateTime CurrentTime { get; internal set; } } /// <summary> /// Subscribe to this event to receive the time acquired by the NTP requests /// </summary> public event EventHandler<TimeReceivedEventArgs> TimeReceived; protected void OnTimeReceived(DateTime time) { if (TimeReceived != null) { TimeReceived(this, new TimeReceivedEventArgs() { CurrentTime = time }); } } /// <summary> /// Not reallu used. I put this here so that I had a list of other NTP servers that could be used. I'll integrate this /// information later and will provide method to allow some one to choose an NTP server. /// </summary> public string[] NtpserverList = new string[] { "pool.ntp.org ", "asia.pool.ntp.org", "europe.pool.ntp.org", "north-america.pool.ntp.org", "oceania.pool.ntp.org", "south-america.pool.ntp.org", "time-a.nist.gov" }; string _serverName; private Socket _socket; /// <summary> /// Constructor allowing an NTP server to be specified /// </summary> /// <param name="serverName">the name of the NTP server to be used</param> public NtpClient(string serverName) { _serverName = serverName; } /// <summary> /// /// </summary> public NtpClient() : this("time-a.nist.gov") { } /// <summary> /// Begins the network communication required to retrieve the time from the NTP server /// </summary> public void RequestTime() { byte[] buffer = new byte[48]; buffer[0] = 0x1B; for (var i = 1; i < buffer.Length; ++i) buffer[i] = 0; DnsEndPoint _endPoint = new DnsEndPoint(_serverName, 123); _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); SocketAsyncEventArgs sArgsConnect = new SocketAsyncEventArgs() { RemoteEndPoint = _endPoint }; sArgsConnect.Completed += (o, e) => { if (e.SocketError == SocketError.Success) { SocketAsyncEventArgs sArgs = new SocketAsyncEventArgs() { RemoteEndPoint = _endPoint }; sArgs.Completed += new EventHandler<SocketAsyncEventArgs>(sArgs_Completed); sArgs.SetBuffer(buffer, 0, buffer.Length); sArgs.UserToken = buffer; _socket.SendAsync(sArgs); } }; _socket.ConnectAsync(sArgsConnect); } void sArgs_Completed(object sender, SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) { byte[] buffer = (byte[])e.Buffer; SocketAsyncEventArgs sArgs = new SocketAsyncEventArgs(); sArgs.RemoteEndPoint = e.RemoteEndPoint; sArgs.SetBuffer(buffer, 0, buffer.Length); sArgs.Completed += (o, a) => { if (a.SocketError == SocketError.Success) { byte[] timeData = a.Buffer; ulong hTime = 0; ulong lTime = 0; for (var i = 40; i <= 43; ++i) hTime = hTime << 8 | buffer[i]; for (var i = 44; i <= 47; ++i) lTime = lTime << 8 | buffer[i]; ulong milliseconds = (hTime * 1000 + (lTime * 1000) / 0x100000000L); TimeSpan timeSpan = TimeSpan.FromTicks((long)milliseconds * TimeSpan.TicksPerMillisecond); var currentTime = new DateTime(1900, 1, 1) + timeSpan; OnTimeReceived(currentTime); } }; _socket.ReceiveAsync(sArgs); } } } 

用法:

 public partial class MainPage : PhoneApplicationPage { private NtpClient _ntpClient; public MainPage() { InitializeComponent(); _ntpClient = new NtpClient(); _ntpClient.TimeReceived += new EventHandler<NtpClient.TimeReceivedEventArgs>(_ntpClient_TimeReceived); } void _ntpClient_TimeReceived(object sender, NtpClient.TimeReceivedEventArgs e) { this.Dispatcher.BeginInvoke(() => { txtCurrentTime.Text = e.CurrentTime.ToLongTimeString(); txtSystemTime.Text = DateTime.Now.ToUniversalTime().ToLongTimeString(); }); } private void UpdateTimeButton_Click(object sender, RoutedEventArgs e) { _ntpClient.RequestTime(); } }