Todo lo que necesito es una forma de consultar un servidor NTP usando C # para obtener la fecha y hora del servidor NTP devuelto como a string
o como a DateTime
.
¿Cómo es esto posible en su forma más simple?
Dado que la antigua respuesta aceptada se eliminó (era un enlace a los resultados de búsqueda de un código de Google que ya no existe), pensé que podría responder esta pregunta para referencia 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: Deberá agregar los siguientes espacios de nombres
using System.Net;
using System.Net.Sockets;
DateTime.ToLocalTime()
socket.Receive(ntpData);
) arrojará una excepción:An existing connection was forcibly closed by the remote host
. Pero todo bien si uso la línea de comandosnet time
para obtener el tiempo.Esta es una versión optimizada de la función que elimina la dependencia de la función BitConverter y la hace compatible con NETMF (.NET Micro Framework)
fuente
socket.ReceiveTimeout = 3000;
... esto evita que se cuelgue si hay un problema de red? El valor está en milisegundos.El kit de herramientas .NET Micro Framework que se encuentra en CodePlex tiene una extensión
NTPClient
. Yo nunca lo he usado, pero se ve bien.También hay otro ejemplo ubicado aquí .
fuente
Sé que el tema es bastante antiguo, pero estas herramientas siempre son útiles. Utilicé los recursos anteriores y creé una versión de NtpClient que permite adquirir de forma asincrónica la hora exacta, en lugar de basarse en eventos.
Uso:
fuente
Una versión modificada para compensar los tiempos de la red y calcular con DateTime-Ticks (más precisa que milisegundos)
fuente
http://www.codeproject.com/Articles/237501/Windows-Phone-NTP-Client funcionará bien para Windows Phone.
Agregar el código relevante
Uso:
fuente
Socket
es unIDisposable
. Debe diseñar su clase con eso en mente y proporcionar una forma de liberar el socket tanto en uso normal como siempre que se genere una excepción. Este código causa pérdidas de memoria