我有这个方法:
public DateTime GetNetworkTime()
{
DateTime networkDateTime = DateTime.Now;
try
{
IPAddress[] addresses = null;
//default Windows time server
const string ntpServer = "time.windows.com";
const string ntpServer1 = "time.nist.gov";
const string ntpServer2 = "time-nw.nist.gov";
const string ntpServer3 = "time-a.nist.gov";
const string ntpServer4 = "time-b.nist.gov";
List<string> ntpServersList = new List<string>();
ntpServersList.Add(ntpServer);
ntpServersList.Add(ntpServer1);
ntpServersList.Add(ntpServer2);
ntpServersList.Add(ntpServer3);
ntpServersList.Add(ntpServer4);
// 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)
for (int i = 0; i < ntpServersList.Count; i++)
{
addresses = Dns.GetHostEntry(ntpServersList[i]).AddressList;
if (addresses.Length > 0)
{
break;
}
}
//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);
Thread th = new Thread(()=>
{
socket.Receive(ntpData);
flag.Set();
});
th.IsBackground = true;
th.Start();
//Block the current thread for 5 seconds
flag.WaitOne(5000, false);
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
networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);
}
catch(Exception err)
{
MessageBox.Show("error" + err.ToString());
}
return networkDateTime.ToLocalTime();
}
在 Form1 的顶部,我做了:
AutoResetEvent flag;
在构造函数中:
flag = new AutoResetEvent(false);
然后在 GetNetworkTime() 上面的方法中,我更改的部分是:
Thread th = new Thread(()=>
{
socket.Receive(ntpData);
flag.Set();
});
th.IsBackground = true;
th.Start();
//Block the current thread for 5 seconds
flag.WaitOne(5000, false);
在使用标志和线程之前,程序被挂起/冻结,我做了 DEBUG > Break All (Pause) 它停在了线上:
socket.Receive(ntpData);
所以我添加了这个标志和线程代码。现在在运行我的程序时,我遇到了这个异常:
socket.Receive(ntpData);
SocketException 阻塞操作被 WSACancelBlockingCall 调用中断
System.Net.Sockets.SocketException was unhandled
HResult=-2147467259
Message=A blocking operation was interrupted by a call to WSACancelBlockingCall
Source=System
ErrorCode=10004
NativeErrorCode=10004
StackTrace:
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.Socket.Receive(Byte[] buffer)
at TestDateTime.Form1.<>c__DisplayClass1.<GetNetworkTime>b__0() in d:\C-Sharp\TestDateTime\TestDateTime\TestDateTime\Form1.cs:line 125
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: