StableVersion4.3/AutomaticTimingWindowsService/SystemTime.cs

124 lines
4.5 KiB
C#
Raw Normal View History

2024-03-11 09:47:34 +08:00
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace AutomaticTimingWindowsService
{
/// <summary>
/// 同步服务器时间
/// </summary>
public class SystemTime
{
/// <summary>
/// 日志文件路径
/// </summary>
static string logPath = Application.StartupPath + @"\Log";
/// <summary>
/// 日志文件
/// </summary>
static FileClass fileClass = new FileClass();
[StructLayout(LayoutKind.Sequential)]
struct NTPTime
{
public short year;
public short month;
public short dayOfWeek;
public short day;
public short hour;
public short minute;
public short second;
public short milliseconds;
}
[DllImport("kernel32.dll")]
private static extern bool SetLocalTime(ref NTPTime time);
private static uint swapEndian(ulong x)
{
return (uint)(((x & 0x000000ff) << 24) +
((x & 0x0000ff00) << 8) +
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24));
}
/// <summary>
/// 设置系统时间
/// </summary>
/// <param name="dt">需要设置的时间</param>
/// <returns>返回系统时间设置状态true为成功false为失败</returns>
private static bool SetLocalDateTime(DateTime dt)
{
NTPTime st;
st.year = (short)dt.Year;
st.month = (short)dt.Month;
st.dayOfWeek = (short)dt.DayOfWeek;
st.day = (short)dt.Day;
st.hour = (short)dt.Hour;
st.minute = (short)dt.Minute;
st.second = (short)dt.Second;
st.milliseconds = (short)dt.Millisecond;
bool rt = SetLocalTime(ref st);
return rt;
}
public static bool Synchronization(string host, out DateTime syncDateTime, out string message)
{
syncDateTime = DateTime.Now;
message = "";
try
{
//if (iPAddress == null)
//{
// var iphostinfo = Dns.GetHostEntry(IPAddress.Parse(host));
// var ntpServer = iphostinfo.AddressList[0];
// iPAddress = ntpServer;
//}
DateTime dtStart = DateTime.Now;
//NTP消息大小摘要是16字节 (RFC 2030)
byte[] ntpData = new byte[48];
//设置跳跃指示器、版本号和模式值
// LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
ntpData[0] = 0x1B;
IPAddress ip = IPAddress.Parse(host);
// NTP服务给UDP分配的端口号是123
IPEndPoint ipEndPoint = new IPEndPoint(ip, 123);
// 使用UTP进行通讯
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Connect(ipEndPoint);
socket.ReceiveTimeout = 3000;
socket.Send(ntpData);
socket.Receive(ntpData);
socket?.Close();
//socket?.Dispose();
DateTime dtEnd = DateTime.Now;
//传输时间戳字段偏移量以64位时间戳格式应答离开客户端服务器的时间
const byte serverReplyTime = 40;
// 获得秒的部分
ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
//获取秒的部分
ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
//由big-endian 到 little-endian的转换
intPart = swapEndian(intPart);
fractPart = swapEndian(fractPart);
ulong milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000UL);
// UTC时间
DateTime webTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds(milliseconds);
//本地时间
DateTime dt = webTime.ToLocalTime();
bool isSuccess = SetLocalDateTime(dt);
syncDateTime = dt;
}
catch (Exception ex)
{
message = ex.Message;
fileClass.WriteLogFile(logPath, "一键校时:\r\n" + ex);
return false;
}
return true;
}
}
}