///
/// 简单网络时间协议服务器
///
public class SNTPServer
{
int port = 123; //服务端口,NTP默认端口123
bool stopFlag = false; //通知后台线程停止消息循环的标识
Thread tdServer; //服务器后台监听线程
///
/// 初始化一个简单网络时间协议服务器
///
public SNTPServer()
: this(123) { }
///
/// 使用指定参数初始化一个简单网络时间协议服务器
///
/// 服务端口
public SNTPServer(int port)
{
this.port = port;
}
///
/// 获取和设置服务端口号
///
public int Port
{
get { return this.port; }
set { this.port = value; }
}
///
/// 启动服务器
///
public void Start()
{
if (tdServer == null || (!tdServer.IsAlive))
{
tdServer = new Thread(bgWork);
tdServer.IsBackground = true;
stopFlag = false;
tdServer.Start();
}
}
///
/// 停止服务器
///
public void Stop()
{
stopFlag = true;
}
private void bgWork()
{
IPEndPoint iep;
UdpClient udpclient;
try
{
iep = new IPEndPoint(IPAddress.Any, port);
udpclient = new UdpClient(iep);
while (!stopFlag)
{
if (udpclient.Available>0)
{
byte[] buffer;
IPEndPoint remoteipEP = new IPEndPoint(IPAddress.Any, port);
buffer = udpclient.Receive(ref remoteipEP);
if (buffer.Length >= 48)
{
NTP.Message msg = (NTP.Message)MarshalExtend.GetObject(buffer, typeof(NTP.Message));
if (msg.Mode == NTP.Mode.Client)
{
NTP.Message reply = new NTP.Message();
reply.OriginateTimestamp = msg.TransmitTimestamp;
reply.ReceiveTimestamp = DateTime.Now;
reply.Mode = NTP.Mode.Server;
reply.VersionNumber = 3;
reply.LeapIndicator = 0;
reply.Stratum = 1;
reply.Poll = 0x0A;
reply.Precision = 0xE9;
reply.RootDelay = 0;
reply.RootDispersion = 0;
reply.ReferenceIdentifier = BitConverter.ToUInt32(new byte[] { 0x41, 0x43, 0x54, 0x53 }, 0);
reply.ReferenceTimestamp = DateTime.Now;
reply.TransmitTimestamp = DateTime.Now;
buffer = MarshalExtend.GetBytes(reply);
udpclient.Send(buffer, buffer.Length, remoteipEP);
}
}
}
}
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.Message, e.Source);
}
}
}
NTP命名空间下,还有几个类
[StructLayout(LayoutKind.Sequential)]
class NtpTime
{
UInt32 seconds;
UInt32 fraction;
static readonly DateTime baseTime = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static implicit operator DateTime(NtpTime time)
{
/* rfc1305的ntp时间中,时间是用64bit来表示的,记录的是1900年后的秒数(utc格式)
* 高32位是整数部分,低32位是小数部分 */
var milliseconds = (int)(((double)ReverseBytes(time.fraction) / uint.MaxValue) * 1000);
return baseTime.AddSeconds(ReverseBytes(time.seconds)).AddMilliseconds(milliseconds).ToLocalTime();
}
public static implicit operator NtpTime(DateTime time)
{
NtpTime ntptime = new NtpTime();
TimeSpan span = DateTime.Now.ToUniversalTime() - baseTime;
ntptime.seconds = ReverseBytes((uint)span.TotalSeconds);
ntptime.fraction = ReverseBytes((uint)((span.TotalSeconds - ntptime.seconds) * uint.MaxValue));
return ntptime;
}
// 翻转字节顺序 (32-bit)
public static UInt32 ReverseBytes(UInt32 value)
{
return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 |
(value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24;
}
public DateTime DateTime
{
get
{
return this;
}
}
}
///
/// 工作模式
///
public enum Mode : byte
{
///
/// 未定义
///
Unknown = 0,
///
/// 主动对等体模式
///
SymmetricActive = 1,
///
/// 被动对等体模式
///
SymmetricPassive = 2,
///
/// 客户端模式
///
Client = 3,
///
/// 服务器模式
///
Server = 4,
///
/// 广播或组播模式
///
Broadcast = 5,
///
/// 控制报文
///
Control = 6,
///
/// 预留给内部使用
///
Reserved = 7
}
///
/// NTP报文
///
[StructLayout(LayoutKind.Sequential)]
class Message
{
byte header;
byte stratum = 1; //系统时钟层数
byte poll = 1; //轮询时间,即两个连续NTP报文之间的时间间隔
byte precision = 1; //系统时钟的精度
UInt32 rootDelay; //本地到主参考时钟源的往返时间
UInt32 rootDispersion; //系统时钟相对于主参考时钟的最大误差
UInt32 referenceIdentifier; //参考时钟源的标识
///
/// 系统时钟最后一次被设定或更新的时间
///
public NtpTime ReferenceTimestamp { get; set; }
///
/// 请求报文离开发送端时发送端的本地时间
///
public NtpTime OriginateTimestamp { get; set; }
///
/// 请求报文到达接收端时接收端的本地时间
///
public NtpTime ReceiveTimestamp { get; set; }
///
/// 应答报文离开应答者时应答者的本地时间
///
public NtpTime TransmitTimestamp { get; set; }
public Message()
{
header = 0xDB;
}
///
/// 获取跳跃指示器
///
public LeapIndicator LeapIndicator
{
get
{
byte val = (byte)(header >> 6);
switch (val)
{
case 0:
return LeapIndicator.NoWarning;
case 1:
return LeapIndicator.LastMinute61;
case 2:
return LeapIndicator.LastMinute59;
case 3:
goto default;
default:
return LeapIndicator.Alarm;
}
}
set
{
header = (byte)((header & 127) | (((byte)value & 3)) << 6);
}
}
///
/// 获取版本号
///
public byte VersionNumber
{
get
{
byte val = (byte)((header & 0x38) >> 3);
return val;
}
set
{
header = (byte)((header & (255 - 56)) | ((value & 7) << 3));
}
}
///
/// 获取工作模式
///
public Mode Mode
{
get
{
byte val = (byte)(header & 0x7);
switch (val)
{
case 0:
goto default;
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;
case 6:
return Mode.Control;
case 7:
return Mode.Reserved;
default:
return Mode.Unknown;
}
}
set
{
header = (byte)((header & (255 - 7)) | ((byte)value & 7));
}
}
///
/// 获取系统时钟层数
///
public byte Stratum
{
get
{
return this.stratum;
}
set
{
this.stratum = value;
}
}
public byte Poll
{
get { return this.poll; }
set { this.poll = value; }
}
public byte Precision
{
get { return this.precision; }
set { this.precision = value; }
}
public uint RootDelay
{
get { return this.rootDelay; }
set { this.rootDelay = value; }
}
public uint RootDispersion
{
get { return this.rootDispersion; }
set { this.rootDispersion = value; }
}
public uint ReferenceIdentifier
{
get { return this.referenceIdentifier; }
set { this.referenceIdentifier = value; }
}
}
///
/// 跳跃指示器(警告在当月最后一天的最终时刻插入的迫近闰秒)
///
public enum LeapIndicator : byte
{
///
/// No warning
///
NoWarning = 0,
LastMinute61 = 1,
LastMinute59 = 2,
///
/// 告警状态(时钟未同步)
///
Alarm = 3
}