Como consultar um servidor NTP usando c #?

Tudo que eu preciso é uma maneira de consultar um servidor NTP usando C # para obter a data e hora do servidor NTP retornado como uma string ou como um DateTime .

Como isso é possível em sua forma mais simples?

Como a antiga resposta aceita foi excluída (era um link para um resultado de pesquisa de código do Google que não existe mais), achei que poderia responder a essa pergunta para referência futura:

 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)); } 

Nota: Você terá que adicionar os seguintes namespaces

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

Esta é uma versão otimizada da function que remove a dependência da function BitConverter e a torna compatível com o 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; } 

O .NET Micro Framework Toolkit encontrado no CodePlex tem um NTPClient . Eu nunca usei isso sozinho, mas parece bom.

Há também outro exemplo localizado aqui .

Eu sei que o tópico é bastante antigo, mas essas ferramentas são sempre úteis. Eu usei os resources acima e criei uma versão do NtpClient que permite de forma assíncrona adquirir um tempo preciso, em vez de um evento baseado em events.

  ///  /// Represents a client which can obtain accurate time via NTP protocol. ///  public class NtpClient { private readonly TaskCompletionSource _resultCompletionSource; ///  /// Creates a new instance of  class. ///  public NtpClient() { _resultCompletionSource = new TaskCompletionSource(); } ///  /// Gets accurate time using the NTP protocol with default timeout of 45 seconds. ///  /// Network accurate  value. public async Task 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  value. public async Task 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  value. public async Task 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)); } } 

Uso:

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

Uma versão modificada para compensar os tempos de rede e calcular com os DateTime-Ticks (mais precisos que milissegundos)

 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 vai funcionar bem para o Windows Phone.

Adicionando o código relevante

 ///  /// 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." ///  public class NtpClient { ///  /// Contains the time returned from the Ntp request ///  public class TimeReceivedEventArgs : EventArgs { public DateTime CurrentTime { get; internal set; } } ///  /// Subscribe to this event to receive the time acquired by the NTP requests ///  public event EventHandler TimeReceived; protected void OnTimeReceived(DateTime time) { if (TimeReceived != null) { TimeReceived(this, new TimeReceivedEventArgs() { CurrentTime = time }); } } ///  /// 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. ///  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; ///  /// Constructor allowing an NTP server to be specified ///  /// the name of the NTP server to be used public NtpClient(string serverName) { _serverName = serverName; } ///  /// ///  public NtpClient() : this("time-a.nist.gov") { } ///  /// Begins the network communication required to retrieve the time from the NTP server ///  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(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); } } } 

Uso:

 public partial class MainPage : PhoneApplicationPage { private NtpClient _ntpClient; public MainPage() { InitializeComponent(); _ntpClient = new NtpClient(); _ntpClient.TimeReceived += new EventHandler(_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(); } }