14 Stimmen

Uhrensynchronisation auf kleinstem Raum ohne NTP

Ich suche ein einfaches Uhrensynchronisationsprotokoll, das leicht zu implementieren ist, wenig Platz benötigt und auch ohne Internetverbindung funktioniert, so dass es z.B. in geschlossenen Labornetzwerken verwendet werden kann. Um das klarzustellen, ich suche nicht nach etwas, das nur dazu verwendet werden kann, Ereignisse zu ordnen (wie Vektoruhren), sondern nach etwas, das es Prozessen auf verschiedenen Knoten ermöglichen würde, ihre Aktionen auf der Grundlage lokaler Uhren zu synchronisieren. Soweit ich das verstehe, würde dies eine Lösung erfordern, die Uhrendrift berücksichtigen kann. Das Vorhandensein von TCP/IP oder ähnlichen Stream-Verbindungen mit relativ geringer Latenz kann vorausgesetzt werden.

11voto

Tails Punkte 3210

Haftungsausschluss: Ich bin beileibe kein NTP-Experte. Ich bin nur ein Hobbyist, der am Wochenende Spaß hat.

Sie sagten, Sie wollten keine NTP-Implementierung, weil sie als zu komplex empfunden wird und weil in Ihrer Umgebung möglicherweise kein Internet-NTP-Server verfügbar ist.

Eine vereinfachte NTP-Suche ist jedoch leicht zu implementieren, und wenn Sie einen lokalen NTP-Server haben, können Sie eine gute Synchronisierung erreichen.

So geht's:

Überprüfung RFC 5905

Die NTP-v4-Pakete sehen etwa so aus:

  • LI (2 Bits)
  • VN (3 Bits) - Verwendung von '100' (4)
  • Modus (3 Bits)
  • Schicht (8 Bits)
  • Abfrage (8 Bits)
  • Genauigkeit (8 Bits)
  • Wurzelverzögerung (32 Bit)
  • Wurzelausbreitung (32 Bit)
  • Referenz-ID (32 Bits)
  • Referenzzeitstempel (64 Bit)
  • Zeitstempel der Herkunft (64 Bit)
  • Zeitstempel des Empfangs (64 Bit)
  • Zeitstempel der Übertragung (64 Bit)
  • Erweiterungsfeld 1 (variabel)
  • Erweiterungsfeld 2 (variabel)
  • ...
  • Schlüsselbezeichner
  • Verschlüsselung (128 Bits)

Der Digest ist nicht erforderlich, so dass die Erstellung einer gültigen Client-Anfrage sehr einfach ist. Entsprechend der Anleitung im RFC verwenden Sie LI = '00', VN = '100' (dezimal 4), Mode = '011' (dezimal 3).

Mit C# zur Veranschaulichung:

byte[] ntpData = new byte[48]
Array.Clear(ntpData, 0, ntpData.Length);
ntpData[0] = 0x23;  // LI = 00, VN = 100, Mode = 011

Öffnen Sie einen Socket zu Ihrem Zielserver und senden Sie ihn.

int ntpPort = 123;
IPEndPoint target = new IPEndPoint(Dns.GetHostEntry(serverDnsName).AddressList[0], ntpPort);
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
s.Connect(target);
s.Send(ntpData);

In der Antwort steht die aktuelle Zeit im Sendezeitstempel (Bytes [40 - 48]). Zeitstempel sind vorzeichenlose 64-Bit-Festkommazahlen. Der ganzzahlige Teil besteht aus den ersten 32 Bits, der gebrochene Teil aus den letzten 32 Bits. Er stellt die Anzahl der Sekunden seit 0h am 1. Januar 1900 dar.

s.Receive(ntpData);
s.Close();

ulong intPart = 0;
ulong fractPart = 0;

for (int i = 0; i < 4; i++)
    intPart = (intPart << 8) | ntpData[40 + i];

for (int i = 4; i < 8; i++)
    fractPart = (fractPart << 8) | ntpData[40 + i];

Um die Uhr mit (ungefährer) Sekundengranularität zu aktualisieren, verwenden Sie: # der Sekunden seit 0h Jan-1-1900 = intPart + (fractPart / 2^32). (Ich sage grob, weil die Netzwerklatenz nicht berücksichtigt wird und wir hier abrunden)

ulong seconds = intPart + (fractPart / 4294967296);

TimeSpan ts = TimeSpan.FromTicks((long)seconds * TimeSpan.TicksPerSecond);

DateTime now = new DateTime(1900, 1, 1);
now = DateTime.SpecifyKind(now, DateTimeKind.Utc);
now += ts;

"now" ist jetzt ein DateTime mit der aktuellen Zeit in UTC.

Auch wenn dies keine Antwort auf Ihre Frage ist, so macht es NTP hoffentlich etwas weniger undurchsichtig =)

6voto

mjr Punkte 1783

Ich war in der Lage, eine abgespeckte Version des Präzisionszeitprotokolls sehr schnell und einfach zu implementieren, allein auf der Grundlage des Wikipedia-Artikels. Wenn Sie nur daran interessiert sind, die Geräte untereinander und nicht mit der Außenwelt zu synchronisieren, sollten Sie mit minimalem Aufwand eine Genauigkeit im Millisekundenbereich erreichen können.

Die wesentlichen Grundlagen des Protokolls sind folgende:

  1. Eine Hauptuhr sendet eine Synchronisationsnachricht mit dem Zeitstempel, wann sie die Nachricht gesendet hat (T1).
  2. Die Clients speichern den Zeitpunkt, zu dem sie die Synchronisationsnachricht erhalten haben, als T1'.
  3. Die Clients senden eine Verzögerungsanforderung an den Master zurück und notieren die Zeit, zu der sie die Nachricht gesendet haben, als T2.
  4. Der Master antwortet auf die Verzögerungsanfrage mit der Zeit, zu der er die Nachricht erhalten hat. Diese Zeit ist T2'.
  5. Der Kunde stellt seine Uhr um (T1' - T1 - T2' + T2)/2 ein.

Wenn Sie eine bessere Stabilität benötigen, können Sie einen Phasenregelkreis oder eine lineare Regression oder etwas Ähnliches implementieren, um den Jitter besser zu kontrollieren und große Schwankungen aufgrund von Netzwerkverzögerungen zu vermeiden. Das Protokoll sieht eine Reihe komplizierterer Funktionen vor, aber ob Sie diese implementieren wollen, hängt davon ab, wie nahe "gut genug" ist.

3voto

Seth Robertson Punkte 29071

Ntp ist das richtige Werkzeug für diese Aufgabe. Sie brauchen keine Internetverbindung, und für zusätzliche 105 Dollar und ein paar Stunden Ihres Lebens können Sie sogar GPS-synchronisiert werden, um eine absolute Zeitreferenz ohne Internetverbindung zu erhalten, obwohl das für Sie offenbar nicht wichtig ist.

Sieht man von der leichten zusätzlichen Komplexität der GPS-Synchronisation ab, kann man sich mit ein paar Zeilen in der Konfigurationsdatei (vier Zeilen auf jedem Client, fünf Zeilen auf dem Server) mit der Uhr des gewählten Systems synchronisieren. Die ntpd-Binärdatei ist auf meinem System 505kB groß. Sie können auch ntpdate verwenden, das regelmäßig ausgeführt werden kann, um die Systemuhr anzupassen (keine Konfigurationszeilen auf dem Client, außer dem Aufruf der ntpdate-Anwendung mit den richtigen Argumenten). Diese Binärdatei ist 80kb groß. Es gibt ein SNTP-Protokoll, das für eingebettete Anwendungen (die mit einem normalen NTP-Server kommunizieren) einen noch kleineren Footprint ermöglicht. Es gibt auch eine alternative NTP-Implementierung namens chrony.

Es gibt auch ein Programm namens rdate (normalerweise nur auf älteren Systemen, obwohl Quelle verfügbar ist), das ähnlich wie ntpdate funktioniert, aber viel weniger präzise. Sie benötigen außerdem einen RFC 868-Server, der oft in inetd enthalten ist.

Die einzige andere Alternative ist das bereits erwähnte Präzisionszeitprotokoll.

2voto

andrewdski Punkte 5029

Macht Präzises Zeitprotokoll die Rechnung passen? Es sieht nicht wirklich einfach aus, aber es scheint mehr oder weniger genau das zu tun, wonach Sie fragen. (Es gibt einige Open-Source-Implementierungen, auf die auf der Wikipedia-Seite verwiesen wird).

Ich denke, das Problem ist, dass es sich hierbei um ein inhärent schwieriges Problem handelt, so dass die Lösungen meist komplex sind. NTP versucht, eine korrekte absolute Zeit zu liefern, was definitiv über das hinausgeht, was Sie brauchen, aber es hat den Vorteil, dass es gut bekannt und weithin implementiert ist.

0voto

Arafangion Punkte 10934

Könnte mit http://www.ietf.org/rfc/rfc5905.txt angemessen sein?

Selbst wenn es viel mehr ist als das, was Sie brauchen, könnten Sie sicherlich einen "kompatiblen" Client implementieren, der mit einem NTP-Server funktioniert (selbst wenn Sie Ihren eigenen NTP-Server betreiben), aber wo die Client-Implementierung absichtlich naiv ist?

Wenn Ihnen z. B. kleine Zeitanpassungen egal sind, sollten Sie sie nicht einführen. Wenn Ihnen die bidirektionale Synchronisation egal ist, implementieren Sie sie nicht usw.

(Seien Sie gewarnt: Die meisten Funktionen in diesem RFC sind nicht ohne Grund vorhanden - die genaue Zeitsynchronisation hat viele Tücken - einschließlich der Tatsache, dass viele Betriebssysteme es nicht mögen, wenn sich die Zeit plötzlich ändert)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X