Zeitsynchronisation

Die meisten Rechneruhren laufen sehr ungenau. Das gilt sowohl für die Hardware-Uhr, /dev/rtc, als auch für die Software-Uhr im Unix kernel. Der Grund liegt in ungenauen Quarzen, die für die Erzeugung der erforderlichen Taktfrequenzen benutzt werden.

Soll die Uhrzeit auf dem Rechner genau sein, ist daher eine regelmäße Synchronisation mit einer externen Zeitreferenz notwendig.

Noch wichtiger als eine in genauer Übereinstimmung mit der gesetzlichen Zeit laufende Rechneruhr ist eine einheitliche Zeit bei mehreren Rechnern in einem lokalen Netz. Dies ist u.a. von Bedeutung wenn

  1. Netzwerk-Filesysteme wie NFS eingesetzt werden. Die time stamps an Dateien (last access time, last modification time, last status change time) werden von dem Rechner erzeugt, auf dem die Dateien liegen. Werden diese time stamps mit dem stat(2) system call von einem anderen Rechner gelesen, dessen Zeit nachgeht, interpretiert er die Zeiten als in der Zukunft liegend.
  2. log files auf verschiedenen Rechnern erzeugt werden. Sind die Rechneruhren nicht synchronisiert, sind die Zeitangaben in den log files nicht vergleichbar und Ereignisse auf verschiedenen Rechnern lassen sich nicht zeitlich zuordnen.

Also sollten die Uhren im Netz untereinander oder sogar mit einer genauen extern Referenz synchronisiert werden. Unter Unix wird dazu allerdings nicht etwa der schon beschriebene system call settimeofday(2) benutzt. Die Zeit mit settimeofday(2) zu setzen hätte zwei Nachteile:

  1. Die Systemzeit würde plötzliche Sprünge machen
  2. Die Systemzeit würde unter Umständen Rückwärtssprünge machen (nämlich dann, wenn die Software-Uhr zu schnell läuft und von Zeit zu Zeit zurückgestellt werden muß).

Beides hätte Nachteile für Programme, die z.B. Zeitmessungen machen, oder in irgendeiner anderen Weise Zeiten aus dem Unix kernel (gettimeofday(2)) oder von Dateien miteinander vergleichen.

Statt settimeofday(2) wird der system call adjtime(2) bzw. moderner adjtimex(2) verwendet. Mit diesem system call kann man dem kernel einen struct timeval übergeben, der ihm mitteilt, um wieviel Mikrosekunden seine Zeit vor- bzw. nachgeht.

Der tick value, der bei Linux/intel x86 normalerweise auf 10000 eingestellt ist, wird dann um 5 Mikrosekunden erhöht bzw. erniedrigt, also auf 10005 bzw. 9995. Damit läuft die Uhr dann um 0.05% schneller bzw. langsamer. Der kernel kann anhand des in adjtime(2) übergebenen Wertes einfach ausrechnen, wie lange er die Uhr schneller bzw. langsamer laufen lassen muß, bis diese Zeitdifferenz ausgeglichen ist. Geht die Uhr z.B. 10ms vor, muß sie bei Linux/i386 für 2000 ticks (also etwa 20 Sekunden lang) langsamer laufen, denn 2000 ticks * 5 µs/tick = 10ms.

timed

Eine schon lange existierende Software zur Synchronisation von Uhren auf Unix-Maschinen in einem LAN (Local Area Network), ist der timed. Dieser daemon wird typischerweise beim Booten im Hintergrund gestartet und tauscht dann regelmäßig Nachrichten mit time stamps mit den anderen time daemons im LAN aus.

Der timed benutzt zum Austausch der Zeitinformation kein eigenes Protokoll sondern bedient sich der ICMP Time Stamp Request/Reply Nachrichten, die normalerweise in einem Unix kernel, sowie auch in vielen anderen Systemen, schon vorhanden sind.

Jedes System im Internet muß ICMP implementiert haben und kennt normalerweise auch ICMP Time Stamps. Wenn eine Maschine im Internet eine ICMP Time Stamp Request erhält, antwortet sie normalerweise mit einem ICMP Time Stamp Reply an den Absender des Request. In der Antwort ist ein 32 Bit langer Wert enthalten, der die Zeit auf dem antwortenden System angibt. Dieser Time Stamp hat aber einige Nachteile:

Der timed besitzt noch einen weiteren Nachteil: Die Time Stamps werden zwar mit ICMP ausgetauscht und können damit beliebig viele Router passieren und jeden Rechner im Internet erreichen, aber timed benutzt UDP broadcast, um geeignete als Server laufende timeds im LAN zu finden, die dann nach ICMP Time Stamps gefragt werden können. Da Broadcasts typischerweise von Routern nicht weitergeleitet werden, ist die Synchronisation mit timed auch auf das LAN beschränkt.

RFC 868

In RFC 868 ist ein weiteres Protokoll zur Zeitsynchronisation von Rechnern beschrieben. Das Protokoll kann sowohl über TCP als auch über UDP benutzt werden und verwendet in beiden Fällen den port 37.

Eine Anfrage eines clients auf dem entsprechenden port wird vom server mit einem 32 bit langen integer beantwortet, der die momentane Zeit darstellt. Die Zeit ist in dem integer kodiert als die Anzahl der Sekunden seit 1900-01-01 0:00:00 UTC, wobei der RFC nicht spezifiziert, ob Schaltsekunden mitgegzählt oder wie in POSIX ignoriert werden.

Auf Unix-Maschinen ist ein server nach RFC 868 normalerweise im inetd(8) implementiert, der einfach die aktuelle Zeit mit time(2) vom kernel besorgt und die Konstante 2208988800 addiert, also die Anzahl der Sekunden zwischen 1900-01-01 und 1970-01-01. Da der von time(2) zurückgegebene time_t normalerweise POSIX-konform Schaltsekunden ignoriert, werden auch von RFC-868-Servern Schaltsekunden meist nicht mitgezählt.

Ein gravierender Nachteil von RFC 868 für die Synchronisation von Rechnern ist die schlechte Genauigkeit der time stamps von nur 1s.

NTP

Alle Nachteile von timed sind in einem neueren Protokoll beseitigt worden. Das Network Time Protocol (NTP) ist von David Mills an der University of Delaware entwickelt worden und u.a. in RFC 1305 beschrieben.

NTP kennt nur ein Paket-Format, mit dem Zeitinformationen zwischen Rechnern ausgetauscht werden. Die NTP-Pakete enthalten im wesentlichen 4 time stamps von jeweils 64 bit:

NTP packet format

Alle Zeiten werden in NTP als binäre 64 bit fixed point Zahlen mit 32 bits vor und 32 bits nach dem Komma dargestellt. Die Zeiten geben die Sekunden an, die seit einem bestimmten festgelegten Zeitpunkt vergangen sind. Dieser Zeitpunkt wurde so festgelegt, daß der Zeitpunkt 1972-01-01 0:00:00 UTC, also die Einführung von UTC, durch die Zahl 2272060800.0 dargestellt wird. Das bedeutet, daß der Zeitpunkt 0.0 der 1. Januar 1900 0:00:00 UTC ist, wenn man UTC entsprechend weit zurück definiert und keine Schaltsekunden vor 1972 annimmt.

Wegen der 32 binären Nachkommastellen ist die Auflösung der in NTP verwendeten Zeitdarstellung 2-32 s, also ca. 233 ps = 233 * 10-12s.

-- Beschreibung des Protokolls: server, client, stratum --

-- Schaltsekunden --

-- xntp und ntp4 --

-- Konfiguration --

-- public NTP server --

Auch die PTB betreibt zwei solche NTP server, ntp1.ptb.de und, ntp2.ptb.de.

DCF-77, GPS, etc.

Wer sich die Zeit per NTP von einem anderen Rechner holen möchte, sollte relativ regelmäße Netzwerkverbindungen haben. Noch besser wäre eine ständig existierende Verbindung zum NTP server.

Die ist aber bei vielen Rechnern, die bei Privatanwendern zu Hause stehen, meist nicht gegeben. Es gibt es auch eine weitere Möglichkeit, an die genaue Zeit zu kommen.

Mit xntp kann man seinen Rechner nicht nur mit anderen Rechnern im Netz mit NTP synchronisieren. Der xntp daemon, xntpd, kann auch mit einer ganzen Reihe von Zeitzeichenempfängern zusammenarbeiten, die typischerweise an die serielle Schnittstelle angeschlossen werden. Diese Empfänger erhalten die Zeit direkt z.B. via Satellit im Falle von GPS (Global Positioning System) oder von einem Langwellensender wie DCF-77, der bei Frankfurt steht und von der PTB betrieben wird, oder WWV, der vom amerikanischen NIST in Boulder, Colorado betrieben wird. Auch über Modems kann Zeitinformation empfangen werden, z.B. wieder von der PTB unter der Nummer 0531-512038, und entsprechende Treiber sind in xntp vohanden. Auch NIST bietet Zeitinformationen über Modem an.

Da GPS-Empfänger recht teuer sind und die Zeitinformation per Modem Telefonkosten verursacht, bietet sich in Deutschland der Empfang der Zeit per DCF-77 an. Solche Empfänger zum Anschluß an die serielle Schnittstelle kann man sich leicht selbst aus Teilen für ca. 40 DM bauen. Schaltplan, Platinenlayout und Beschreibung der Schaltung gibt's auch hier. Man braucht dann nur noch eine freie serielle Schnittstelle. Evtl. muß man dazu noch eine Schnittstellenkarte besorgen, wenn an den beiden auf dem mainboard meistens vorhandenen seriellen Schnittstellen schon Maus und Modem hängen.

DCF-77

Der DCF-77-Sender sendet ein amplitudenmoduliertes Signal auf einem 77.5kHz-Träger. Die Amplitude wird beim Beginn jeder Sekunde auf 25% abgesenkt. Auf diesem Wert bleibt sie für 100 ms oder 200 ms und geht dann wieder auf 100%, und zwar für die nächsten 900 ms bzw. 800 ms bis zum Beginn der nächsten Sekunde.

DCF-77-Signal

Die Absenkung des Signals wird in der 59. Sekunde jeder Minute ausgelassen, um die Synchronisation mit dem Minutenbeginn zu ermöglichen. Wenn also eine fallende Flanke erst nach 1800 ms oder mehr nach der letzten Flanke empfangen wird, stellt sie einen Minutenbeginn dar.

Durch die fallenden Flanken zum Beginn der Sekunde bietet das Signal daher die Möglichkeit, sich mit dem Sekundentakt zu synchronisieren.

Außerdem wird jede Sekunde ein Bit an Information übertragen. Dauert die Absenkung der Amplitude 100 ms, wurde eine 0 übertragen, anderenfalls eine 1.

Pro Minute werden daher also 59 Bits an Information übertragen. Diese 59 Bits geben die Minute, Stunde, Tag, Monat, Jahr und Wochentag der nächsten Minute an. Außerdem sind in den 59 Bits auch Informationen über Winter-/Sommerzeit sowie Schaltsekunden enthalten.

Diese Informationen werden vom entsprechenden Treiber im xntpd genutzt, um die genaue Zeit zu ermittlen und die Software-Uhr des Unix kernels mittels adjtime(2) mit der von DCF-77 gesendeten Zeit zu synchronisieren.

Wie gut diese Synchronisation ist, hängt vor allem davon ab, wie gut der verwendete DCF-77-Empfänger ist, d.h. wie genau die fallenden Flanken am Ausgang des Empfängers tatsächlich zum Sekundenbeginn auftreten.

GPS

...