我只需要一种使用C#查询NTP服务器的方法,以便将NTP服务器的日期时间作为a string
或a 返回DateTime
.
这最简单的形式怎么可能?
由于旧的已接受的答案被删除(这是一个不再存在的Google代码搜索结果的链接),我想我可以回答这个问题以供将来参考:
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 Toolkit有一个NTPClient
.我自己从未使用它,但它看起来不错.
还有位于另一个例子在这里.
我知道这个主题很老了,但这些工具总是很方便.我已经使用了上面的资源并创建了一个NtpClient版本,它允许异步获取准确的时间,而不是基于事件.
////// Represents a client which can obtain accurate time via NTP protocol. /// public class NtpClient { private readonly TaskCompletionSource_resultCompletionSource; /// /// Creates a new instance of public NtpClient() { _resultCompletionSource = new TaskCompletionSourceclass. /// (); } /// /// Gets accurate time using the NTP protocol with default timeout of 45 seconds. /// ///Network accurate public async Taskvalue. GetNetworkTimeAsync() { return await GetNetworkTimeAsync(TimeSpan.FromSeconds(45)); } /// /// Gets accurate time using the NTP protocol with default timeout of 45 seconds. /// /// Operation timeout in milliseconds. ///Network accurate public async Taskvalue. GetNetworkTimeAsync(int timeoutMs) { return await GetNetworkTimeAsync(TimeSpan.FromMilliseconds(timeoutMs)); } /// /// Gets accurate time using the NTP protocol with default timeout of 45 seconds. /// /// Operation timeout. ///Network accurate public async Taskvalue. 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 }