Gehe zu deutscher Webseite

ViaThinkSoft CodeLib

This article is in:
CodeLibProgramming aidsC#


using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Linq;

namespace ConsoleApp6
{

    class Program
    {


        public class AtomzeitAsync
        {
            public struct Atomzeit
            {
                public string server;
                public DateTime zeit;
            }

            protected static DateTime GetNetworkTime(string ntpServer, bool utc = false)
            {
                // https://stackoverflow.com/questions/1193955/how-to-query-an-ntp-server-using-c

                // 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 utc ? networkDateTime : networkDateTime.ToLocalTime();
            }

            private static uint SwapEndianness(ulong x)
            {
                // https://stackoverflow.com/questions/1193955/how-to-query-an-ntp-server-using-c
                // stackoverflow.com/a/3294698/162671
                return (uint)(((x & 0x000000ff) << 24) +
                               ((x & 0x0000ff00) << 8) +
                               ((x & 0x00ff0000) >> 8) +
                               ((x & 0xff000000) >> 24));
            }

            static AtomzeitAsync()
            {
                string zeitServerFile = "TimeserverNTP.txt";
                if (File.Exists(zeitServerFile))
                {
                    bool containsSomething = false;
                    var lines = File.ReadAllLines(zeitServerFile);
                    foreach (var line in lines)
                    {
                        if (line.Trim() == "") continue;
                        if (line.Trim().Substring(0, 1) == "#") continue;
                        containsSomething = true;
                        break;
                    }
                    if (containsSomething)
                    {
                        Array.Resize(ref servers, 0);
                        foreach (var line in lines)
                        {
                            if (line.Trim() == "") continue;
                            if (line.Trim().Substring(0, 1) == "#") continue;
                            Array.Resize(ref servers, servers.Length + 1);
                            servers[servers.Length - 1] = line.Trim();
                        }
                    }
                }
                else
                {
                    string[] dummyList = { };
                    File.WriteAllLines(zeitServerFile, dummyList.ToList());
                }
            }
            public static string[] servers = {
        "ptbtime1.ptb.de",
        "ptbtime2.ptb.de",
        "ptbtime3.ptb.de"
        };

            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(() =>
                {
                    // Variable für Fehlermeldungen
                    string errors = null;

                    try
                    {
                        Atomzeit res = new Atomzeit();
                        res.server = serverIp;
                        res.zeit = GetNetworkTime(serverIp, utc);
                        return res;
                    }
                    catch (Exception ex)
                    {
                        // Fehler dokumentieren
                        if (errors != null) errors += "\r\n";
                        errors += "Fehler bei der Abfrage von '" +
                           serverIp + ": " + ex.Message;
                    }

                    // 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