📄 ntpclient.cs
字号:
/*
* NTPClient
* Copyright (C)2001 Valer BOCAN <vbocan@dataman.ro>
* Last modified: June 29, 2001
* All Rights Reserved
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* To fully understand the concepts used herein, I strongly
* recommend that you read the RFC 2030.
*
* NOTE: This example is intended to be compiled with Visual Studio .NET Beta 2
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace SDP
{
/// <summary>
/// Leap indicator field values
/// </summary>
public enum LeapIndicators
{
/// <summary>
/// 0 - No warning
/// </summary>
NoWarning,
/// <summary>
/// 1 - Last minute has 61 seconds
/// </summary>
LastMinute61,
/// <summary>
/// 2 - Last minute has 59 seconds
/// </summary>
LastMinute59,
/// <summary>
/// 3 - Alarm condition (clock not synchronized)
/// </summary>
Alarm
}
/// <summary>
/// Mode field values
/// </summary>
public enum Modes
{
/// <summary>
/// 1 - Symmetric active
/// </summary>
SymmetricActive,
/// <summary>
/// 2 - Symmetric pasive
/// </summary>
SymmetricPassive,
/// <summary>
/// 3 - Client
/// </summary>
Client,
/// <summary>
/// 4 - Server
/// </summary>
Server,
/// <summary>
/// 5 - Broadcast
/// </summary>
Broadcast,
/// <summary>
/// 0, 6, 7 - Reserved
/// </summary>
Unknown
}
/// <summary>
/// Stratum field values
/// </summary>
public enum Stratums
{
/// <summary>
/// 0 - unspecified or unavailable
/// </summary>
Unspecified,
/// <summary>
/// 1 - primary reference (e.g. radio-clock)
/// </summary>
PrimaryReference,
/// <summary>
/// 2-15 - secondary reference (via NTP or SNTP)
/// </summary>
SecondaryReference,
/// <summary>
/// 16-255 - reserved
/// </summary>
Reserved
}
/// <summary>
/// NTPClient is a C# class designed to connect to time servers on the Internet.
/// The implementation of the protocol is based on the RFC 2030.
///
/// Public class members:
///
/// LeapIndicator - Warns of an impending leap second to be inserted/deleted in the last
/// minute of the current day. (See the _LeapIndicator enum)
///
/// VersionNumber - Version number of the protocol (3 or 4).
///
/// Mode - Returns mode. (See the _Mode enum)
///
/// Stratum - Stratum of the clock. (See the _Stratum enum)
///
/// PollInterval - Maximum interval between successive messages.
///
/// Precision - Precision of the clock.
///
/// RootDelay - Round trip time to the primary reference source.
///
/// RootDispersion - Nominal error relative to the primary reference source.
///
/// ReferenceID - Reference identifier (either a 4 character string or an IP address).
///
/// ReferenceTimestamp - The time at which the clock was last set or corrected.
///
/// OriginateTimestamp - The time at which the request departed the client for the server.
///
/// ReceiveTimestamp - The time at which the request arrived at the server.
///
/// Transmit Timestamp - The time at which the reply departed the server for client.
///
/// RoundTripDelay - The time between the departure of request and arrival of reply.
///
/// LocalClockOffset - The offset of the local clock relative to the primary reference
/// source.
///
/// Initialize - Sets up data structure and prepares for connection.
///
/// Connect - Connects to the time server and populates the data structure.
/// It can also set the system time.
///
/// IsResponseValid - Returns true if received data is valid and if comes from
/// a NTP-compliant time server.
///
/// ToString - Returns a string representation of the object.
///
/// -----------------------------------------------------------------------------
/// Structure of the standard NTP header (as described in RFC 2030)
/// 1 2 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// |LI | VN |Mode | Stratum | Poll | Precision |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Root Delay |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Root Dispersion |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Reference Identifier |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// | Reference Timestamp (64) |
/// | |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// | Originate Timestamp (64) |
/// | |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// | Receive Timestamp (64) |
/// | |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// | Transmit Timestamp (64) |
/// | |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Key Identifier (optional) (32) |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | |
/// | |
/// | Message Digest (optional) (128) |
/// | |
/// | |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
///
/// -----------------------------------------------------------------------------
///
/// NTP Timestamp Format (as described in RFC 2030)
/// 1 2 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Seconds |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Seconds Fraction (0-padded) |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
///
/// </summary>
public class NTPClient
{
// NTP Data Structure Length
private const byte NTPDataLength = 48;
// NTP Data Structure (as described in RFC 2030)
byte[] NTPData = new byte[NTPDataLength];
// Offset constants for timestamps in the data structure
private const byte offReferenceID = 12;
private const byte offReferenceTimestamp = 16;
private const byte offOriginateTimestamp = 24;
private const byte offReceiveTimestamp = 32;
private const byte offTransmitTimestamp = 40;
/// <summary>
/// Gets the Leap Indicator.
/// </summary>
public LeapIndicators LeapIndicator
{
get
{
// Isolate the two most significant bits
byte val = (byte)(NTPData[0] >> 6);
switch (val)
{
case 0: return LeapIndicators.NoWarning;
case 1: return LeapIndicators.LastMinute61;
case 2: return LeapIndicators.LastMinute59;
case 3: goto default;
default:
return LeapIndicators.Alarm;
}
}
}
/// <summary>
/// Gets the version number.
/// </summary>
public byte VersionNumber
{
get
{
// Isolate bits 3 - 5
byte val = (byte)((NTPData[0] & 0x38) >> 3);
return val;
}
}
/// <summary>
/// Gets the mode.
/// </summary>
public Modes Mode
{
get
{
// Isolate bits 0 - 3
byte val = (byte)(NTPData[0] & 0x7);
switch (val)
{
case 0: goto default;
case 6: goto default;
case 7: goto default;
default:
return Modes.Unknown;
case 1:
return Modes.SymmetricActive;
case 2:
return Modes.SymmetricPassive;
case 3:
return Modes.Client;
case 4:
return Modes.Server;
case 5:
return Modes.Broadcast;
}
}
}
/// <summary>
/// Gets the Stratum.
/// </summary>
public Stratums Stratum
{
get
{
byte val = (byte)NTPData[1];
if (val == 0) return Stratums.Unspecified;
else
if (val == 1) return Stratums.PrimaryReference;
else
if (val <= 15) return Stratums.SecondaryReference;
else
return Stratums.Reserved;
}
}
/// <summary>
/// Gets the Poll Interval.
/// </summary>
public uint PollInterval
{
get
{
return (uint)Math.Round(Math.Pow(2, NTPData[2]));
}
}
/// <summary>
/// Gets the precision in milliseconds.
/// </summary>
public double Precision
{
get
{
return (1000 * Math.Pow(2, NTPData[3]));
}
}
/// <summary>
/// Gets the root delay in milliseconds.
/// </summary>
public double RootDelay
{
get
{
int temp = 0;
temp = 256 * (256 * (256 * NTPData[4] + NTPData[5]) + NTPData[6]) + NTPData[7];
return 1000 * (((double)temp) / 0x10000);
}
}
/// <summary>
/// Gets the root dispersion in milliseconds.
/// </summary>
public double RootDispersion
{
get
{
int temp = 0;
temp = 256 * (256 * (256 * NTPData[8] + NTPData[9]) + NTPData[10]) + NTPData[11];
return 1000 * (((double)temp) / 0x10000);
}
}
/// <summary>
/// Gets the reference identifier.
/// </summary>
public string ReferenceID
{
get
{
string val = "";
switch (Stratum)
{
case Stratums.Unspecified:
goto case Stratums.PrimaryReference;
case Stratums.PrimaryReference:
val += (char)NTPData[offReferenceID + 0];
val += (char)NTPData[offReferenceID + 1];
val += (char)NTPData[offReferenceID + 2];
val += (char)NTPData[offReferenceID + 3];
break;
case Stratums.SecondaryReference:
switch (VersionNumber)
{
case 3: // Version 3, Reference ID is an IPv4 address
string Address = NTPData[offReferenceID + 0].ToString() + "." +
NTPData[offReferenceID + 1].ToString() + "." +
NTPData[offReferenceID + 2].ToString() + "." +
NTPData[offReferenceID + 3].ToString();
try
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -