根据Time Protocol从NIST Internet Time Servers获取准确时间_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > 根据Time Protocol从NIST Internet Time Servers获取准确时间

根据Time Protocol从NIST Internet Time Servers获取准确时间

 2017/9/8 12:08:50  小兵备用  程序员俱乐部  我要评论(0)
  • 摘要:TimeProtocol(RFC-868)是一种非常简单的应用层协议:它返回一个32位的二进制数字,这个数字描述了从1900年1月1日0时0分0秒到现在的秒数,服务器在TCP的37号端口监听时间协议请求。本函数将服务器返回值转化成本地时间。先前不知道有现成的IPAddress.NetworkToHostOrder函数,所以自己直接写了个ReverseBytes函数,把字节数组从Big-endian转换为Little-endian。这个函数可能在其他地方也有用,所以索性就留着了
  • 标签:Server net internet

Time Protocol(RFC-868)是一种非常简单的应用层协议它返回一个32位的二进制数字,这个数字描述了从1900年1月1日0时0分0秒到现在的秒数,服务器在TCP的37号端口监听时间协议请求。本函数将服务器返回值转化成本地时间。

先前不知道有现成的IPAddress.NetworkToHostOrder函数,所以自己直接写了个ReverseBytes函数,把字节数组从Big-endian转换为Little-endian。这个函数可能在其他地方也有用,所以索性就留着了。

 

 1 private const int BUFSIZE = 4;      //字符数组的大小
 2         private const int PORT = 37;        //服务器端口号
 3         private const int TIMEOUT = 3000;   //超时时间(毫秒)
 4         private const int MAXTRIES = 3;     //尝试接受数据的次数
 5 
 6         /// <summary>
 7         /// 从NIST Internet Time Servers获取准确时间。
 8         /// </summary>
 9         /// <param name="dateTime">返回准确的本地时间</param>
10         /// <param name="timeServer">服务器列表</param>
11         /// <returns>获取时间失败将返回false,否则返回true</returns>
12         public static bool GetDateTimeFromTimeServer(out DateTime now, string timeServers = "time.nist.gov")
13         {
14             Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
15             //设置获取超时时间
16             socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, TIMEOUT);
17 
18             byte[] rcvBytes = new byte[BUFSIZE];    //接收数据的字节数组
19             int tries = 0;                          //记录尝试次数
20             bool received = false;                  //接收是否成功
21             int totalBytesRcvd = 0;                 //总共接收的字节数
22             int bytesRcvd = 0;                      //本次接收的字节数
23             do
24             {
25                 try
26                 {
27                     socket.Connect(Dns.GetHostEntry(timeServers).AddressList, PORT);
28                     while ((bytesRcvd = socket.Receive(rcvBytes, totalBytesRcvd, BUFSIZE - totalBytesRcvd, SocketFlags.None)) > 0)
29                     {
30                         totalBytesRcvd += bytesRcvd;
31                     }
32                     received = true;
33                 }
34                 catch (SocketException)
35                 {
36                     //超时或者其他Socket错误,增加参数次数
37                     tries++;
38                 }
39             } while ((!received) && (tries < MAXTRIES));
40             socket.Close();
41 
42             if (received)
43             {
44                 //将字节数组从Big-endian转换为Little-endian
45                 //ReverseBytes(ref rcvBytes, 0, 4);
46                 //UInt32 seconds = BitConverter.ToUInt32(rcvBytes, 0);
47                 UInt32 seconds = BitConverter.ToUInt32(rcvBytes, 0);
48                 seconds = (UInt32)IPAddress.NetworkToHostOrder((int)seconds);
49                 //从1900年1月1日0时0分0秒日期加上获取的秒数并转换到当前本地时区时间
50                 now = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(seconds).ToLocalTime();
51                 return true;
52             }
53             else
54             {
55                 now = DateTime.Now;
56                 return false;
57             }
58         }
59 
60         /// <summary>
61         /// 翻转byte数组的字节顺序
62         /// </summary>
63         /// <param name="bytes">要翻转的字节数组</param>
64         /// <param name="start">规定转换起始位置</param>
65         /// <param name="len">要翻转的长度</param>
66         private static void ReverseBytes(ref byte[] bytes, int start, int len)
67         {
68             if ((start < 0) || (start > bytes.Length - 1) || (len > bytes.Length))
69             {
70                 throw new ArgumentOutOfRangeException();
71             }
72 
73             int end = start + len - 1;
74             if (end > bytes.Length)
75             {
76                 throw new ArgumentOutOfRangeException();
77             }
78 
79             byte tmp;
80             for (int i = 0, index = start; index < start + len / 2; index++, i++)
81             {
82                 tmp = bytes[end - i];
83                 bytes[end - i] = bytes[index];
84                 bytes[index] = tmp;
85             }
86         }

 

代码未经过严格测试,如果有什么错误,欢迎指出,谢谢!

 

参考文献

[1]陈香凝,王烨阳,陈婷婷,张铮.Windows网络与通信程序设计第三版[M].人民邮电出版社,2017:27-28.

[2]D.Makofske,M.Donahoo,K.Calvert.TCPIP Sockets in C# Practical Guide for Programmers[M].Morgan Kaufmann.2004。

[3]NIST Internet Time Servers.http://tf.nist.gov/tf-cgi/servers.cgi.

发表评论
用户名: 匿名