Ich benötige lediglich eine Möglichkeit, einen NTP-Server mit C # abzufragen, um die Datums- und Uhrzeitangabe des NTP-Servers als a string
oder als zurückzugeben DateTime
.
Wie ist das in seiner einfachsten Form möglich?
Da die alte akzeptierte Antwort gelöscht wurde (es war ein Link zu einem Google-Code-Suchergebnis, der nicht mehr existiert), dachte ich, ich könnte diese Frage als zukünftige Referenz beantworten:
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));
}
Hinweis: Sie müssen die folgenden Namespaces hinzufügen
using System.Net;
using System.Net.Sockets;
DateTime.ToLocalTime()
socket.Receive(ntpData);
Es wird eine Ausnahme auslösen :An existing connection was forcibly closed by the remote host
. Aber alles in Ordnung, wenn ich die Kommandozeile benutzenet time
, um die Zeit zu bekommen.Dies ist eine optimierte Version der Funktion, die die Abhängigkeit von der BitConverter-Funktion beseitigt und sie mit NETMF (.NET Micro Framework) kompatibel macht.
quelle
socket.ReceiveTimeout = 3000;
... wird verhindert, dass sie bei einem Netzwerkproblem hängen bleibt. Der Wert wird in Millisekunden angegeben.Das im CodePlex enthaltene .NET Micro Framework Toolkit verfügt über eine
NTPClient
. Ich habe es selbst nie benutzt, aber es sieht gut aus.Es gibt auch ein weiteres Beispiel befindet sich hier .
quelle
Ich weiß, dass das Thema ziemlich alt ist, aber solche Tools sind immer praktisch. Ich habe die oben genannten Ressourcen verwendet und eine Version von NtpClient erstellt, mit der asynchron statt ereignisbasiert die genaue Zeit erfasst werden kann.
Verwendung:
quelle
Eine modifizierte Version zum Kompensieren von Netzwerkzeiten und Berechnen mit DateTime-Ticks (genauer als Millisekunden)
quelle
http://www.codeproject.com/Articles/237501/Windows-Phone-NTP-Client wird für Windows Phone gut funktionieren.
Hinzufügen des entsprechenden Codes
Verwendung :
quelle
Socket
ist einIDisposable
. Sie sollten Ihre Klasse unter diesem Gesichtspunkt entwerfen und eine Möglichkeit bereitstellen, den Socket sowohl bei normalem Gebrauch als auch immer dann freizugeben, wenn eine Ausnahme ausgelöst wird. Dieser Code verursacht Speicherlecks