using
System;
using System.Net;
using System.Net.Sockets;
namespace SNTPTime
{
// Leap indicator field values
public enum _LeapIndicator
{
NoWarning, // 0 - No warning
LastMinute61, // 1 - Last minute has 61 seconds
LastMinute59, // 2 - Last minute has 59 seconds
Alarm // 3 - Alarm condition (clock not synchronized)
}
// Mode field values
public enum _Mode
{
SymmetricActive, // 1 - Symmetric active
SymmetricPassive, // 2 - Symmetric pasive
Client, // 3 - Client
Server, // 4 - Server
Broadcast, // 5 - Broadcast
Unknown // 0, 6, 7 - Reserved
}
// Stratum field values
public enum _Stratum
{
Unspecified, // 0 - unspecified or unavailable
PrimaryReference, // 1 - primary reference (e.g. radio-clock)
SecondaryReference, // 2-15 - secondary reference (via NTP or SNTP)
Reserved // 16-255 - reserved
}
/// <summary>
/// SNTPTimeClient 的摘要说明。
///
/// 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.
///
/// 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 SNTPTimeClient
{
// 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 ;
// Leap Indicator
public _LeapIndicator LeapIndicator
{
get
{
// Isolate the two most significant bits
byte val = ( byte )(NTPData[ 0 ] >> 6 );
switch (val)
{
case 0 : return _LeapIndicator.NoWarning;
case 1 : return _LeapIndicator.LastMinute61;
case 2 : return _LeapIndicator.LastMinute59;
case 3 :
default :
return _LeapIndicator.Alarm;
}
}
}
// Version Number
public byte VersionNumber
{
get
{
// Isolate bits 3 - 5
byte val = ( byte )((NTPData[ 0 ] & 0x38 ) >> 3 );
return val;
}
}
// Mode
public _Mode Mode
{
get
{
// Isolate bits 0 - 3
byte val = ( byte )(NTPData[ 0 ] & 0x7 );
switch (val)
{
case 0 :
case 6 :
case 7 :
default :
return _Mode.Unknown;
case 1 :
return _Mode.SymmetricActive;
case 2 :
return _Mode.SymmetricPassive;
case 3 :
return _Mode.Client;
case 4 :
return _Mode.Server;
case 5 :
return _Mode.Broadcast;
}
}
}
// Stratum
public _Stratum Stratum
{
get
{
byte val = ( byte )NTPData[ 1 ];
if (val == 0 ) return _Stratum.Unspecified;
else
if (val == 1 ) return _Stratum.PrimaryReference;
else
if (val <= 15 ) return _Stratum.SecondaryReference;
else
return _Stratum.Reserved;
}
}
// Poll Interval
public uint PollInterval
{
get
{
return ( uint )Math.Round(Math.Pow( 2 , NTPData[ 2 ]));
}
}
// Precision (in milliseconds)
public double Precision
{
get
{
return ( 1000 * Math.Pow( 2 , NTPData[ 3 ]));
}
}
// Root Delay (in milliseconds)
public double RootDelay
{
get
{
int temp = 0 ;
temp = 256 * ( 256 * ( 256 * NTPData[ 4 ] + NTPData[ 5 ]) + NTPData[ 6 ]) + NTPData[ 7 ];
return 1000 * ((( double )temp) / 0x10000 );
}
}
// Root Dispersion (in milliseconds)
public double RootDispersion
{
get
{
int temp = 0 ;
temp = 256 * ( 256 * ( 256 * NTPData[ 8 ] + NTPData[ 9 ]) + NTPData[ 10 ]) + NTPData[ 11 ];
return 1000 * ((( double )temp) / 0x10000 );
}
}
// Reference Identifier
public string ReferenceID
{
get
{
string val = "" ;
switch (Stratum)
{
case _Stratum.Unspecified:
case _Stratum.PrimaryReference:
val += Convert.ToChar(NTPData[offReferenceID + 0 ]);
val += Convert.ToChar(NTPData[offReferenceID + 1 ]);
val += Convert.ToChar(NTPData[offReferenceID + 2 ]);
val += Convert.ToChar(NTPData[offReferenceID + 3 ]);
break ;
case _Stratum.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
/// / {
/// / IPAddress RefAddr = new IPAddress(Address);
/// / IPHostEntry Host = DNS.GetHostByAddr(RefAddr);
/// / val = Host.Hostname + " (" + Address + ")";
/// / }
/// / catch(Exception)
/// / {
/// / val = "N/A";
/// / }
/// /
/// / break;
/// / case 4: // Version 4, Reference ID is the timestamp of last update
/// / DateTime time = ComputeDate(GetMilliSeconds(offReferenceID));
/// / // Take care of the time zone
/// / long offset = TimeZone.CurrentTimeZone.GetUTCOffset(DateTime.Now);
/// / TimeSpan offspan = TimeSpan.FromTicks(offset);
/// / val = (time + offspan).ToString();
/// / break;
/// / default:
/// / val = "N/A";
/// / }
break ;
}
return val;
}
}
// Reference Timestamp
public DateTime ReferenceTimestamp
{
get
{
DateTime time = ComputeDate(GetMilliSeconds(offReferenceTimestamp));
// Take care of the time zone
long offset = Convert.ToInt64(TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now));
TimeSpan offspan = TimeSpan.FromTicks(offset);
return time + offspan;
}
}
// Originate Timestamp
public DateTime OriginateTimestamp
{
get
{
return ComputeDate(GetMilliSeconds(offOriginateTimestamp));
}
}
// Receive Timestamp
public DateTime ReceiveTimestamp
{
get
{
DateTime time = ComputeDate(GetMilliSeconds(offReceiveTimestamp));
// Take care of the time zone
long offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Ticks;
TimeSpan offspan = TimeSpan.FromTicks(offset);
return time + offspan;
}
}
// Transmit Timestamp
public DateTime TransmitTimestamp
{
get
{
DateTime time = ComputeDate(GetMilliSeconds(offTransmitTimestamp));
// Take care of the time zone
long offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Ticks;
TimeSpan offspan = TimeSpan.FromTicks(offset);
return time + offspan;
}
set
{
SetDate(offTransmitTimestamp, value);
}
}
// Reception Timestamp
public DateTime ReceptionTimestamp;
// Round trip delay (in milliseconds)
public int RoundTripDelay
{
get
{
TimeSpan span = (ReceiveTimestamp - OriginateTimestamp) + (ReceptionTimestamp - TransmitTimestamp);
return ( int )span.TotalMilliseconds;
}
}
// Local clock offset (in milliseconds)
public int LocalClockOffset
{
get
{
TimeSpan span = (ReceiveTimestamp - OriginateTimestamp) - (ReceptionTimestamp - TransmitTimestamp);
return ( int )(span.TotalMilliseconds / 2 );
}
}
// Compute date, given the number of milliseconds since January 1, 1900
private DateTime ComputeDate( ulong milliseconds)
{
TimeSpan span = TimeSpan.FromMilliseconds(( double )milliseconds);
DateTime time = new DateTime( 1900 , 1 , 1 );
time += span;
return time;
}
// Compute the number of milliseconds, given the offset of a 8-byte array
private ulong GetMilliSeconds( byte offset)
{
ulong intpart = 0 , fractpart = 0 ;
for ( int i = 0 ; i <= 3 ; i ++ )
{
intpart = 256 * intpart + NTPData[offset + i];
}
for ( int i = 4 ; i <= 7 ; i ++ )
{
fractpart = 256 * fractpart + NTPData[offset + i];
}
ulong milliseconds = intpart * 1000 + (fractpart * 1000 ) / 0x100000000L ;
return milliseconds;
}
// Compute the 8-byte array, given the date
private void SetDate( byte offset, DateTime date)
{
ulong intpart = 0 , fractpart = 0 ;
DateTime StartOfCentury = new DateTime( 1900 , 1 , 1 , 0 , 0 , 0 ); // January 1, 1900 12:00 AM
ulong milliseconds = ( ulong )(date - StartOfCentury).TotalMilliseconds;
intpart = milliseconds / 1000 ;
fractpart = ((milliseconds % 1000 ) * 0x100000000L ) / 1000 ;
ulong temp = intpart;
for ( int i = 3 ; i >= 0 ; i -- )
{
NTPData[offset + i] = ( byte )(temp % 256 );
temp = temp / 256 ;
}
temp = fractpart;
for ( int i = 7 ; i >= 4 ; i -- )
{
NTPData[offset + i] = ( byte )(temp % 256 );
temp = temp / 256 ;
}
}
// Initialize the NTPClient data
private void Initialize()
{
// Set version number to 4 and Mode to 3 (client)
NTPData[ 0 ] = 0x1B ;
// Initialize all other fields with 0
for ( int i = 1 ; i < 48 ; i ++ )
{
NTPData[i] = 0 ;
}
// Initialize the transmit timestamp
TransmitTimestamp = DateTime.Now;
}
// Connect to the time server
public void Connect()
{
try
{
IPAddress hostadd = IPAddress.Parse(TimeServer);
IPEndPoint EPhost = new IPEndPoint(hostadd, Convert.ToInt32(TimePort));
UdpClient TimeSocket = new UdpClient();
TimeSocket.Connect(EPhost);
Initialize();
TimeSocket.Send(NTPData, NTPData.Length);
NTPData = TimeSocket.Receive( ref EPhost);
if ( ! IsResponseValid())
{
throw new Exception( " Invalid response from " + TimeServer);
}
ReceptionTimestamp = DateTime.Now;
}
catch (SocketException e)
{
throw new Exception(e.Message);
}
}
// Check if the response from server is valid
public bool IsResponseValid()
{
if (NTPData.Length < NTPDataLength || Mode != _Mode.Server)
{
return false ;
}
else
{
return true ;
}
}
// Converts the object to string
public override string ToString()
{
string str;
str = " Leap Indicator: " ;
switch (LeapIndicator)
{
case _LeapIndicator.NoWarning:
str += " No warning " ;
break ;
case _LeapIndicator.LastMinute61:
str += " Last minute has 61 seconds " ;
break ;
case _LeapIndicator.LastMinute59:
str += " Last minute has 59 seconds " ;
break ;
case _LeapIndicator.Alarm:
str += " Alarm Condition (clock not synchronized) " ;
break ;
}
str += " /r/nVersion number: " + VersionNumber.ToString() + " /r/n " ;
str += " Mode: " ;
switch (Mode)
{
case _Mode.Unknown:
str += " Unknown " ;
break ;
case _Mode.SymmetricActive:
str += " Symmetric Active " ;
break ;
case _Mode.SymmetricPassive:
str += " Symmetric Pasive " ;
break ;
case _Mode.Client:
str += " Client " ;
break ;
case _Mode.Server:
str += " Server " ;
break ;
case _Mode.Broadcast:
str += " Broadcast " ;
break ;
}
str += " /r/nStratum: " ;
switch (Stratum)
{
case _Stratum.Unspecified:
case _Stratum.Reserved:
str += " Unspecified " ;
break ;
case _Stratum.PrimaryReference:
str += " Primary Reference " ;
break ;
case _Stratum.SecondaryReference:
str += " Secondary Reference " ;
break ;
}
str += " /r/nLocal time: " + TransmitTimestamp.ToString();
str += " /r/nPrecision: " + Precision.ToString() + " ms " ;
str += " /r/nPoll Interval: " + PollInterval.ToString() + " s " ;
str += " /r/nReference ID: " + ReferenceID.ToString();
str += " /r/nRoot Dispersion: " + RootDispersion.ToString() + " ms " ;
str += " /r/nRound Trip Delay: " + RoundTripDelay.ToString() + " ms " ;
str += " /r/nLocal Clock Offset: " + LocalClockOffset.ToString() + " ms " ;
str += " /r/n " ;
return str;
}
// The URL of the time server we're connecting to
private string TimeServer;
private string TimePort;
public SNTPTimeClient( string host, string port)
{
TimeServer = host;
TimePort = port;
}
}
}
using System.Net;
using System.Net.Sockets;
namespace SNTPTime
{
// Leap indicator field values
public enum _LeapIndicator
{
NoWarning, // 0 - No warning
LastMinute61, // 1 - Last minute has 61 seconds
LastMinute59, // 2 - Last minute has 59 seconds
Alarm // 3 - Alarm condition (clock not synchronized)
}
// Mode field values
public enum _Mode
{
SymmetricActive, // 1 - Symmetric active
SymmetricPassive, // 2 - Symmetric pasive
Client, // 3 - Client
Server, // 4 - Server
Broadcast, // 5 - Broadcast
Unknown // 0, 6, 7 - Reserved
}
// Stratum field values
public enum _Stratum
{
Unspecified, // 0 - unspecified or unavailable
PrimaryReference, // 1 - primary reference (e.g. radio-clock)
SecondaryReference, // 2-15 - secondary reference (via NTP or SNTP)
Reserved // 16-255 - reserved
}
/// <summary>
/// SNTPTimeClient 的摘要说明。
///
/// 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.
///
/// 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 SNTPTimeClient
{
// 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 ;
// Leap Indicator
public _LeapIndicator LeapIndicator
{
get
{
// Isolate the two most significant bits
byte val = ( byte )(NTPData[ 0 ] >> 6 );
switch (val)
{
case 0 : return _LeapIndicator.NoWarning;
case 1 : return _LeapIndicator.LastMinute61;
case 2 : return _LeapIndicator.LastMinute59;
case 3 :
default :
return _LeapIndicator.Alarm;
}
}
}
// Version Number
public byte VersionNumber
{
get
{
// Isolate bits 3 - 5
byte val = ( byte )((NTPData[ 0 ] & 0x38 ) >> 3 );
return val;
}
}
// Mode
public _Mode Mode
{
get
{
// Isolate bits 0 - 3
byte val = ( byte )(NTPData[ 0 ] & 0x7 );
switch (val)
{
case 0 :
case 6 :
case 7 :
default :
return _Mode.Unknown;
case 1 :
return _Mode.SymmetricActive;
case 2 :
return _Mode.SymmetricPassive;
case 3 :
return _Mode.Client;
case 4 :
return _Mode.Server;
case 5 :
return _Mode.Broadcast;
}
}
}
// Stratum
public _Stratum Stratum
{
get
{
byte val = ( byte )NTPData[ 1 ];
if (val == 0 ) return _Stratum.Unspecified;
else
if (val == 1 ) return _Stratum.PrimaryReference;
else
if (val <= 15 ) return _Stratum.SecondaryReference;
else
return _Stratum.Reserved;
}
}
// Poll Interval
public uint PollInterval
{
get
{
return ( uint )Math.Round(Math.Pow( 2 , NTPData[ 2 ]));
}
}
// Precision (in milliseconds)
public double Precision
{
get
{
return ( 1000 * Math.Pow( 2 , NTPData[ 3 ]));
}
}
// Root Delay (in milliseconds)
public double RootDelay
{
get
{
int temp = 0 ;
temp = 256 * ( 256 * ( 256 * NTPData[ 4 ] + NTPData[ 5 ]) + NTPData[ 6 ]) + NTPData[ 7 ];
return 1000 * ((( double )temp) / 0x10000 );
}
}
// Root Dispersion (in milliseconds)
public double RootDispersion
{
get
{
int temp = 0 ;
temp = 256 * ( 256 * ( 256 * NTPData[ 8 ] + NTPData[ 9 ]) + NTPData[ 10 ]) + NTPData[ 11 ];
return 1000 * ((( double )temp) / 0x10000 );
}
}
// Reference Identifier
public string ReferenceID
{
get
{
string val = "" ;
switch (Stratum)
{
case _Stratum.Unspecified:
case _Stratum.PrimaryReference:
val += Convert.ToChar(NTPData[offReferenceID + 0 ]);
val += Convert.ToChar(NTPData[offReferenceID + 1 ]);
val += Convert.ToChar(NTPData[offReferenceID + 2 ]);
val += Convert.ToChar(NTPData[offReferenceID + 3 ]);
break ;
case _Stratum.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
/// / {
/// / IPAddress RefAddr = new IPAddress(Address);
/// / IPHostEntry Host = DNS.GetHostByAddr(RefAddr);
/// / val = Host.Hostname + " (" + Address + ")";
/// / }
/// / catch(Exception)
/// / {
/// / val = "N/A";
/// / }
/// /
/// / break;
/// / case 4: // Version 4, Reference ID is the timestamp of last update
/// / DateTime time = ComputeDate(GetMilliSeconds(offReferenceID));
/// / // Take care of the time zone
/// / long offset = TimeZone.CurrentTimeZone.GetUTCOffset(DateTime.Now);
/// / TimeSpan offspan = TimeSpan.FromTicks(offset);
/// / val = (time + offspan).ToString();
/// / break;
/// / default:
/// / val = "N/A";
/// / }
break ;
}
return val;
}
}
// Reference Timestamp
public DateTime ReferenceTimestamp
{
get
{
DateTime time = ComputeDate(GetMilliSeconds(offReferenceTimestamp));
// Take care of the time zone
long offset = Convert.ToInt64(TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now));
TimeSpan offspan = TimeSpan.FromTicks(offset);
return time + offspan;
}
}
// Originate Timestamp
public DateTime OriginateTimestamp
{
get
{
return ComputeDate(GetMilliSeconds(offOriginateTimestamp));
}
}
// Receive Timestamp
public DateTime ReceiveTimestamp
{
get
{
DateTime time = ComputeDate(GetMilliSeconds(offReceiveTimestamp));
// Take care of the time zone
long offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Ticks;
TimeSpan offspan = TimeSpan.FromTicks(offset);
return time + offspan;
}
}
// Transmit Timestamp
public DateTime TransmitTimestamp
{
get
{
DateTime time = ComputeDate(GetMilliSeconds(offTransmitTimestamp));
// Take care of the time zone
long offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now).Ticks;
TimeSpan offspan = TimeSpan.FromTicks(offset);
return time + offspan;
}
set
{
SetDate(offTransmitTimestamp, value);
}
}
// Reception Timestamp
public DateTime ReceptionTimestamp;
// Round trip delay (in milliseconds)
public int RoundTripDelay
{
get
{
TimeSpan span = (ReceiveTimestamp - OriginateTimestamp) + (ReceptionTimestamp - TransmitTimestamp);
return ( int )span.TotalMilliseconds;
}
}
// Local clock offset (in milliseconds)
public int LocalClockOffset
{
get
{
TimeSpan span = (ReceiveTimestamp - OriginateTimestamp) - (ReceptionTimestamp - TransmitTimestamp);
return ( int )(span.TotalMilliseconds / 2 );
}
}
// Compute date, given the number of milliseconds since January 1, 1900
private DateTime ComputeDate( ulong milliseconds)
{
TimeSpan span = TimeSpan.FromMilliseconds(( double )milliseconds);
DateTime time = new DateTime( 1900 , 1 , 1 );
time += span;
return time;
}
// Compute the number of milliseconds, given the offset of a 8-byte array
private ulong GetMilliSeconds( byte offset)
{
ulong intpart = 0 , fractpart = 0 ;
for ( int i = 0 ; i <= 3 ; i ++ )
{
intpart = 256 * intpart + NTPData[offset + i];
}
for ( int i = 4 ; i <= 7 ; i ++ )
{
fractpart = 256 * fractpart + NTPData[offset + i];
}
ulong milliseconds = intpart * 1000 + (fractpart * 1000 ) / 0x100000000L ;
return milliseconds;
}
// Compute the 8-byte array, given the date
private void SetDate( byte offset, DateTime date)
{
ulong intpart = 0 , fractpart = 0 ;
DateTime StartOfCentury = new DateTime( 1900 , 1 , 1 , 0 , 0 , 0 ); // January 1, 1900 12:00 AM
ulong milliseconds = ( ulong )(date - StartOfCentury).TotalMilliseconds;
intpart = milliseconds / 1000 ;
fractpart = ((milliseconds % 1000 ) * 0x100000000L ) / 1000 ;
ulong temp = intpart;
for ( int i = 3 ; i >= 0 ; i -- )
{
NTPData[offset + i] = ( byte )(temp % 256 );
temp = temp / 256 ;
}
temp = fractpart;
for ( int i = 7 ; i >= 4 ; i -- )
{
NTPData[offset + i] = ( byte )(temp % 256 );
temp = temp / 256 ;
}
}
// Initialize the NTPClient data
private void Initialize()
{
// Set version number to 4 and Mode to 3 (client)
NTPData[ 0 ] = 0x1B ;
// Initialize all other fields with 0
for ( int i = 1 ; i < 48 ; i ++ )
{
NTPData[i] = 0 ;
}
// Initialize the transmit timestamp
TransmitTimestamp = DateTime.Now;
}
// Connect to the time server
public void Connect()
{
try
{
IPAddress hostadd = IPAddress.Parse(TimeServer);
IPEndPoint EPhost = new IPEndPoint(hostadd, Convert.ToInt32(TimePort));
UdpClient TimeSocket = new UdpClient();
TimeSocket.Connect(EPhost);
Initialize();
TimeSocket.Send(NTPData, NTPData.Length);
NTPData = TimeSocket.Receive( ref EPhost);
if ( ! IsResponseValid())
{
throw new Exception( " Invalid response from " + TimeServer);
}
ReceptionTimestamp = DateTime.Now;
}
catch (SocketException e)
{
throw new Exception(e.Message);
}
}
// Check if the response from server is valid
public bool IsResponseValid()
{
if (NTPData.Length < NTPDataLength || Mode != _Mode.Server)
{
return false ;
}
else
{
return true ;
}
}
// Converts the object to string
public override string ToString()
{
string str;
str = " Leap Indicator: " ;
switch (LeapIndicator)
{
case _LeapIndicator.NoWarning:
str += " No warning " ;
break ;
case _LeapIndicator.LastMinute61:
str += " Last minute has 61 seconds " ;
break ;
case _LeapIndicator.LastMinute59:
str += " Last minute has 59 seconds " ;
break ;
case _LeapIndicator.Alarm:
str += " Alarm Condition (clock not synchronized) " ;
break ;
}
str += " /r/nVersion number: " + VersionNumber.ToString() + " /r/n " ;
str += " Mode: " ;
switch (Mode)
{
case _Mode.Unknown:
str += " Unknown " ;
break ;
case _Mode.SymmetricActive:
str += " Symmetric Active " ;
break ;
case _Mode.SymmetricPassive:
str += " Symmetric Pasive " ;
break ;
case _Mode.Client:
str += " Client " ;
break ;
case _Mode.Server:
str += " Server " ;
break ;
case _Mode.Broadcast:
str += " Broadcast " ;
break ;
}
str += " /r/nStratum: " ;
switch (Stratum)
{
case _Stratum.Unspecified:
case _Stratum.Reserved:
str += " Unspecified " ;
break ;
case _Stratum.PrimaryReference:
str += " Primary Reference " ;
break ;
case _Stratum.SecondaryReference:
str += " Secondary Reference " ;
break ;
}
str += " /r/nLocal time: " + TransmitTimestamp.ToString();
str += " /r/nPrecision: " + Precision.ToString() + " ms " ;
str += " /r/nPoll Interval: " + PollInterval.ToString() + " s " ;
str += " /r/nReference ID: " + ReferenceID.ToString();
str += " /r/nRoot Dispersion: " + RootDispersion.ToString() + " ms " ;
str += " /r/nRound Trip Delay: " + RoundTripDelay.ToString() + " ms " ;
str += " /r/nLocal Clock Offset: " + LocalClockOffset.ToString() + " ms " ;
str += " /r/n " ;
return str;
}
// The URL of the time server we're connecting to
private string TimeServer;
private string TimePort;
public SNTPTimeClient( string host, string port)
{
TimeServer = host;
TimePort = port;
}
}
}
调用:
SNTPTime.SNTPTimeClient client
=
new
SNTPTime.SNTPTimeClient(
"
210.72.145.44
"
,
"
123
"
);
client.Connect();
string strTest = client.ToString();
client.Connect();
string strTest = client.ToString();
原文摘自: http://www.cnblogs.com/easydata/archive/2008/04/01/1132917.html