根据Time Protocol从NIST Internet Time Servers…
2018-06-22 04:45:11来源:未知 阅读 ()
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 if (BitConverter.IsLittleEndian) 49 { 50 seconds = (UInt32)IPAddress.NetworkToHostOrder((int)seconds); 51 } 52 //从1900年1月1日0时0分0秒日期加上获取的秒数并转换到当前本地时区时间 53 now = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(seconds).ToLocalTime(); 54 return true; 55 } 56 else 57 { 58 now = DateTime.Now; 59 return false; 60 } 61 } 62 63 /// <summary> 64 /// 翻转byte数组的字节顺序 65 /// </summary> 66 /// <param name="bytes">要翻转的字节数组</param> 67 /// <param name="start">规定转换起始位置</param> 68 /// <param name="len">要翻转的长度</param> 69 private static void ReverseBytes(ref byte[] bytes, int start, int len) 70 { 71 if ((start < 0) || (start > bytes.Length - 1) || (len > bytes.Length)) 72 { 73 throw new ArgumentOutOfRangeException(); 74 } 75 76 int end = start + len - 1; 77 if (end > bytes.Length) 78 { 79 throw new ArgumentOutOfRangeException(); 80 } 81 82 byte tmp; 83 for (int i = 0, index = start; index < start + len / 2; index++, i++) 84 { 85 tmp = bytes[end - i]; 86 bytes[end - i] = bytes[index]; 87 bytes[index] = tmp; 88 } 89 }
代码未经过严格测试,如果有什么错误,欢迎指出,谢谢!
参考文献
[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.
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇:c#中Socket网络通信的入门
- php根据用户语言跳转相应网页 2019-12-09
- php根据操作系统转换文件名大小写的方法 2019-10-12
- [TCP/IP] ping traceroute和TTL 2019-07-23
- 身份证验证PHP类 2019-07-23
- PHP监听Socket 2019-06-24
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash