How to Query an NTP Server using C#?

前端 未结 6 2063
一生所求
一生所求 2020-11-22 03:09

All I need is a way to query an NTP Server using C# to get the Date Time of the NTP Server returned as either a string or as a DateTime.

H

6条回答
  •  说谎
    说谎 (楼主)
    2020-11-22 03:54

    Since the old accepted answer got deleted (It was a link to a Google code search results that no longer exist), I figured I could answer this question for future reference :

    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));
    }
    

    Note: You will have to add the following namespaces

    using System.Net;
    using System.Net.Sockets;
    

提交回复
热议问题