简版网络时间服务(SNTP)的实现C#

    xiaoxiao2023-10-10  153

    /// <summary> /// 简单网络时间协议服务器 /// </summary> public class SNTPServer { int port = 123; //服务端口,NTP默认端口123 bool stopFlag = false; //通知后台线程停止消息循环的标识 Thread tdServer; //服务器后台监听线程 /// <summary> /// 初始化一个简单网络时间协议服务器 /// </summary> public SNTPServer() : this(123) { } /// <summary> /// 使用指定参数初始化一个简单网络时间协议服务器 /// </summary> /// <param name="port">服务端口</param> public SNTPServer(int port) { this.port = port; } /// <summary> /// 获取和设置服务端口号 /// </summary> public int Port { get { return this.port; } set { this.port = value; } } /// <summary> /// 启动服务器 /// </summary> public void Start() { if (tdServer == null || (!tdServer.IsAlive)) { tdServer = new Thread(bgWork); tdServer.IsBackground = true; stopFlag = false; tdServer.Start(); } } /// <summary> /// 停止服务器 /// </summary> 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; } } } /// <summary> /// 工作模式 /// </summary> public enum Mode : byte { /// <summary> /// 未定义 /// </summary> Unknown = 0, /// <summary> /// 主动对等体模式 /// </summary> SymmetricActive = 1, /// <summary> /// 被动对等体模式 /// </summary> SymmetricPassive = 2, /// <summary> /// 客户端模式 /// </summary> Client = 3, /// <summary> /// 服务器模式 /// </summary> Server = 4, /// <summary> /// 广播或组播模式 /// </summary> Broadcast = 5, /// <summary> /// 控制报文 /// </summary> Control = 6, /// <summary> /// 预留给内部使用 /// </summary> Reserved = 7 } /// <summary> /// NTP报文 /// </summary> [StructLayout(LayoutKind.Sequential)] class Message { byte header; byte stratum = 1; //系统时钟层数 byte poll = 1; //轮询时间,即两个连续NTP报文之间的时间间隔 byte precision = 1; //系统时钟的精度 UInt32 rootDelay; //本地到主参考时钟源的往返时间 UInt32 rootDispersion; //系统时钟相对于主参考时钟的最大误差 UInt32 referenceIdentifier; //参考时钟源的标识 /// <summary> /// 系统时钟最后一次被设定或更新的时间 /// </summary> public NtpTime ReferenceTimestamp { get; set; } /// <summary> /// 请求报文离开发送端时发送端的本地时间 /// </summary> public NtpTime OriginateTimestamp { get; set; } /// <summary> /// 请求报文到达接收端时接收端的本地时间 /// </summary> public NtpTime ReceiveTimestamp { get; set; } /// <summary> /// 应答报文离开应答者时应答者的本地时间 /// </summary> public NtpTime TransmitTimestamp { get; set; } public Message() { header = 0xDB; } /// <summary> /// 获取跳跃指示器 /// </summary> 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); } } /// <summary> /// 获取版本号 /// </summary> public byte VersionNumber { get { byte val = (byte)((header & 0x38) >> 3); return val; } set { header = (byte)((header & (255 - 56)) | ((value & 7) << 3)); } } /// <summary> /// 获取工作模式 /// </summary> 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)); } } /// <summary> /// 获取系统时钟层数 /// </summary> 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; } } } /// <summary> /// 跳跃指示器(警告在当月最后一天的最终时刻插入的迫近闰秒) /// </summary> public enum LeapIndicator : byte { /// <summary> /// No warning /// </summary> NoWarning = 0, LastMinute61 = 1, LastMinute59 = 2, /// <summary> /// 告警状态(时钟未同步) /// </summary> Alarm = 3 }

     

    最新回复(0)