C#内网NTP时间同步源码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using System.Diagnostics;
namespace WindowsFormsApp3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DateTime aa = MGetNetworkTime();
textBox1.Text = aa.ToString("yyyy-MM-dd HH:mm:ss");
if (textBox1.Text == "1900-12-31 00:00:00")
{ }
else {
string times = aa.ToString("yyyy-MM-dd HH:mm:ss");
DateTimeSynchronization dt = new DateTimeSynchronization();
if (dt.SetLocalTimeByStr(times))
{
MessageBox.Show("修改成功");
}
else
{
MessageBox.Show("修改失败");
}
}
}
public DateTime MGetNetworkTime()
{
try
{
//default Windows time server
const string ntpServer = "time.windows.com"; //对于无法访问外网NTP服务器的,可以在内网假设NTP服务器,同时修改hosts文件
// NTP message size - 16 bytes of the digest (RFC 2030)
var ntpData = new byte[48];
//Setting the Leap Indicator, Version Number and Mode values
ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
var addresses = Dns.GetHostEntry(ntpServer).AddressList;
//The UDP port number assigned to NTP is 123
var ipEndPoint = new IPEndPoint(addresses[0], 123);
//NTP uses UDP
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Connect(ipEndPoint);
socket.Send(ntpData);
socket.Receive(ntpData);
socket.Close();
//Offset to get to the "Transmit Timestamp" field (time at which the reply
//departed the server for the client, in 64-bit timestamp format."
const byte serverReplyTime = 40;
//Get the seconds part
ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);
//Get the seconds fraction
ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);
//Convert From big-endian to little-endian
intPart = SwapEndianness(intPart);
fractPart = SwapEndianness(fractPart);
var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
//**UTC** time
var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);
return networkDateTime.ToLocalTime();
}
catch (Exception e)
{
MessageBox.Show(e.Message+"请重试");
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false;//是否使用操作系统shell启动
p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
p.StartInfo.CreateNoWindow = true;//不显示程序窗口
p.Start();//启动程序
string strCMD = "echo 172.16.0.99 time.windows.com >C:\\Windows\\System32\\drivers\\etc\\hosts";
p.StandardInput.WriteLine(strCMD + "&exit");
p.StandardInput.AutoFlush = true;
//获取cmd窗口的输出信息
string output = p.StandardOutput.ReadToEnd();
//等待程序执行完退出进程
p.WaitForExit();
p.Close();
return Convert.ToDateTime("12-31-1900");
}
}
uint SwapEndianness(ulong x)
{
return (uint)(((x & 0x000000ff) << 24) +
((x & 0x0000ff00) << 8) +
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24));
}
public class DateTimeSynchronization
{
[StructLayout(LayoutKind.Sequential)]
public struct SystemTime
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMiliseconds;
}
public class Win32
{
[DllImport("Kernel32.dll")]
public static extern bool SetSystemTime(ref SystemTime sysTime);
[DllImport("Kernel32.dll")]
public static extern bool SetLocalTime(ref SystemTime sysTime);
[DllImport("Kernel32.dll")]
public static extern void GetSystemTime(ref SystemTime sysTime);
[DllImport("Kernel32.dll")]
public static extern void GetLocalTime(ref SystemTime sysTime);
}
public bool SetLocalTimeByStr(string timestr)
{
bool flag = false;
SystemTime sysTime = new SystemTime();
string SysTime = timestr.Trim(); //此步骤多余,为方便程序而用直接用timestr即可
sysTime.wYear = Convert.ToUInt16(SysTime.Substring(0, 4));
sysTime.wMonth = Convert.ToUInt16(SysTime.Substring(5, 2));
sysTime.wDay = Convert.ToUInt16(SysTime.Substring(8, 2));
sysTime.wHour = Convert.ToUInt16(SysTime.Substring(11, 2));
sysTime.wMinute = Convert.ToUInt16(SysTime.Substring(14, 2));
sysTime.wSecond = Convert.ToUInt16(SysTime.Substring(17, 2));
//注意:
//结构体的wDayOfWeek属性一般不用赋值,函数会自动计算,写了如果不对应反而会出错
//wMiliseconds属性默认值为一,可以赋值
try
{
flag = Win32.SetLocalTime(ref sysTime);
}
//由于不是C#本身的函数,很多异常无法捕获
//函数执行成功则返回true,函数执行失败返回false
//经常不返回异常,不提示错误,但是函数返回false,给查找错误带来了一定的困难
catch (Exception ex1)
{
Console.WriteLine("SetLocalTime函数执行异常" + ex1.Message);
}
return flag;
}
}
private void button2_Click(object sender, EventArgs e)
{
}
private void label1_Click(object sender, EventArgs e)
{
}
}
}