ViaThinkSoft CodeLib
This article is in:
CodeLib → Programming aids → C#
ATTENTION: The DayTime-Protocol is outdated! Please use the NTP variant here.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Net.Sockets;
namespace ConsoleApp6
{
class Program
{
public class AtomzeitAsync
{
public struct Atomzeit
{
public string server;
public DateTime zeit;
}
public static string[] servers = { "time-a.nist.gov", "time-b.nist.gov", "time.nist.gov", "utcnist.colorado.edu", "nist1.datum.com" };
public static Atomzeit? GetAtomzeit(int timeout = 1000)
{
List<Task<Atomzeit>> tasks = new List<Task<Atomzeit>>();
int bakWorkerThreads = 0;
int bakCompletionPortThreads = 0;
ThreadPool.GetMinThreads(out bakWorkerThreads, out bakCompletionPortThreads);
ThreadPool.SetMinThreads(bakWorkerThreads + servers.Length, bakCompletionPortThreads + servers.Length);
try
{
for (int i = 0; i < servers.Length; i++)
{
tasks.Add(GetFileLengthsAsync(servers[i], false));
}
Thread.Sleep(timeout);
for (int ctr = 0; ctr < tasks.Count; ctr++)
{
if (tasks[ctr].Status == TaskStatus.RanToCompletion)
{
return tasks[ctr].Result;
}
}
return null;
}
finally
{
ThreadPool.SetMinThreads(bakWorkerThreads, bakCompletionPortThreads);
}
}
private static Task<Atomzeit> GetFileLengthsAsync(string serverIp, bool utc)
{
return Task.Factory.StartNew/*Task.Run*/(() =>
{
// Variable für Fehlermeldungen
string errors = null;
TcpClient tcpClient = null;
try
{
// TcpClient erzeugen und den Empfangs-Timeout auf eine Sekunde
// setzen
tcpClient = new TcpClient();
tcpClient.ReceiveTimeout = 1000;
// Versuch zum aktuellen Server eine Verbindung aufzubauen
tcpClient.Connect(serverIp, 13);
// Den NetworkStream referenzieren
NetworkStream networkStream = tcpClient.GetStream();
string result = null;
if (networkStream.CanWrite && networkStream.CanRead)
{
// Das Ergebnis empfangen und in ASCII konvertieren
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
try
{
networkStream.Read(bytes, 0,
(int)tcpClient.ReceiveBufferSize);
result = Encoding.ASCII.GetString(bytes);
}
catch (Exception ex)
{
// Fehler dokumentieren
if (errors != null) errors += "\r\n";
errors += "Fehler bei der Abfrage von '" + serverIp +
": " + ex.Message;
}
}
if (result != null)
{
// Das Ergebnis, das die Form JJJJJ YR-MO-DA HH:MM:SS TT L H msADV
// UTC(NIST) OTM besitzt, in einzelne Token aufsplitten
string[] token = result.Split(' ');
// Anzahl der Token überprüfen
if (token.Length >= 6)
{
// Den Health-Status auslesen und überprüfen
string health = token[5];
if (health == "0")
{
// Alles ok: Datums- und Zeitangaben auslesen
string[] dates = token[1].Split('-');
string[] times = token[2].Split(':');
// DateTime-Instanz mit diesen Daten erzeugen
System.DateTime utcDate =
new System.DateTime(Int32.Parse(dates[0]) + 2000,
Int32.Parse(dates[1]), Int32.Parse(dates[2]),
Int32.Parse(times[0]), Int32.Parse(times[1]),
Int32.Parse(times[2]));
// Lokale Zeit berechnen und zurückgeben
if (utc)
{
Atomzeit res = new Atomzeit();
res.server = serverIp;
res.zeit = utcDate;
return res;
}
else
{
Atomzeit res = new Atomzeit();
res.server = serverIp;
res.zeit = TimeZone.CurrentTimeZone.ToLocalTime(utcDate);
return res;
}
}
else
{
// Fehler dokumentieren
if (errors != null) errors += "\r\n";
errors += "Fehler bei der Abfrage von '" + serverIp +
": Der Health-Status ist " + health;
}
}
else
{
// Fehler dokumentieren
if (errors != null) errors += "\r\n";
errors += "Fehler bei der Abfrage von '" + serverIp +
": Die Anzahl der Token ist kleiner als 6";
}
}
}
catch (Exception ex)
{
// Fehler dokumentieren
if (errors != null) errors += "\r\n";
errors += "Fehler bei der Abfrage von '" +
serverIp + ": " + ex.Message;
}
finally
{
try
{
// TcpClient schließen
tcpClient.Close();
}
catch { }
}
// Wenn die Methode hier ankommt, sind bei allen Abfragen
// Fehler aufgetreten, also eine Ausnahme werfen
throw new Exception(errors);
});
}
}
public static void Main()
{
AtomzeitAsync.Atomzeit? az = AtomzeitAsync.GetAtomzeit();
if (az == null)
{
Console.WriteLine("Atomzeit konnte nicht ermittelt werden");
}
else
{
Console.WriteLine("Atomzeit: {0} gemeldet durch {1}", ((AtomzeitAsync.Atomzeit)az).zeit, ((AtomzeitAsync.Atomzeit)az).server);
}
Console.ReadLine();
}
}
}
Daniel Marschall
ViaThinkSoft Co-Founder
ViaThinkSoft Co-Founder