根据Time Protocol从NIST Internet Time Servers获取准确时间
Time Protocol(RFC-868)是一种非常简单的应用层协议:它返回一个32位的二进制数字,这个数字描述了从1900年1月1日0时0分0秒到现在的秒数,服务器在TCP的37号端口监听时间协议请求。本函数将服务器返回值转化成本地时间。
先前不知道有现成的IPAddress.NetworkToHostOrder函数,所以自己直接写了个ReverseBytes函数,把字节数组从Big-endian转换为Little-endian。这个函数可能在其他地方也有用,所以索性就留着了。
private const int BUFSIZE = ; //字符数组的大小
private const int PORT = ; //服务器端口号
private const int TIMEOUT = ; //超时时间(毫秒)
private const int MAXTRIES = ; //尝试接受数据的次数 /// <summary>
/// 从NIST Internet Time Servers获取准确时间。
/// </summary>
/// <param name="dateTime">返回准确的本地时间</param>
/// <param name="timeServer">服务器列表</param>
/// <returns>获取时间失败将返回false,否则返回true</returns>
public static bool GetDateTimeFromTimeServer(out DateTime now, string timeServers = "time.nist.gov")
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//设置获取超时时间
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, TIMEOUT); byte[] rcvBytes = new byte[BUFSIZE]; //接收数据的字节数组
int tries = ; //记录尝试次数
bool received = false; //接收是否成功
int totalBytesRcvd = ; //总共接收的字节数
int bytesRcvd = ; //本次接收的字节数
do
{
try
{
socket.Connect(Dns.GetHostEntry(timeServers).AddressList, PORT);
while ((bytesRcvd = socket.Receive(rcvBytes, totalBytesRcvd, BUFSIZE - totalBytesRcvd, SocketFlags.None)) > )
{
totalBytesRcvd += bytesRcvd;
}
received = true;
}
catch (SocketException)
{
//超时或者其他Socket错误,增加参数次数
tries++;
}
} while ((!received) && (tries < MAXTRIES));
socket.Close(); if (received)
{
//将字节数组从Big-endian转换为Little-endian
//ReverseBytes(ref rcvBytes, 0, 4);
//UInt32 seconds = BitConverter.ToUInt32(rcvBytes, 0);
UInt32 seconds = BitConverter.ToUInt32(rcvBytes, );
if (BitConverter.IsLittleEndian)
{
seconds = (UInt32)IPAddress.NetworkToHostOrder((int)seconds);
}
//从1900年1月1日0时0分0秒日期加上获取的秒数并转换到当前本地时区时间
now = new DateTime(, , , , , , DateTimeKind.Utc).AddSeconds(seconds).ToLocalTime();
return true;
}
else
{
now = DateTime.Now;
return false;
}
} /// <summary>
/// 翻转byte数组的字节顺序
/// </summary>
/// <param name="bytes">要翻转的字节数组</param>
/// <param name="start">规定转换起始位置</param>
/// <param name="len">要翻转的长度</param>
private static void ReverseBytes(ref byte[] bytes, int start, int len)
{
if ((start < ) || (start > bytes.Length - ) || (len > bytes.Length))
{
throw new ArgumentOutOfRangeException();
} int end = start + len - ;
if (end > bytes.Length)
{
throw new ArgumentOutOfRangeException();
} byte tmp;
for (int i = , index = start; index < start + len / ; index++, i++)
{
tmp = bytes[end - i];
bytes[end - i] = bytes[index];
bytes[index] = tmp;
}
}
代码未经过严格测试,如果有什么错误,欢迎指出,谢谢!
参考文献
[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.
根据Time Protocol从NIST Internet Time Servers获取准确时间的更多相关文章
- Java获取NTP网络时间
最近项目中涉及到一个时间验证的问题,需要根据当前时间来验证业务数据是否过期.所以直接写代码如下: new java.util.Date().getTime(); 结果测试的时候出现了 ...
- Websocket 与代理服务器如何交互? How HTML5 Web Sockets Interact With Proxy Servers
How HTML5 Web Sockets Interact With Proxy Servers Posted by Peter Lubberson Mar 16, 2010 With the re ...
- Common Internet File System
CIFS (Common Internet File System) is a protocol that gained popularity around the year 2000, as ven ...
- 【计算机网络】-网络层-Internet的网络层
[计算机网络]-网络层-Internet的网络层 Internet是一组相互连接的网络或者自治系统的集合 Internet 1.存在几个主要骨干网络,骨干网络是由高带宽的线路和快速路由器构成 2.这些 ...
- 《TCP/IP详解卷1:协议》第6章 ICMP:Internet控制报文协议-读书笔记
章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...
- [Database] Deadlock avoidance protocol
如何避免Deadlock,如果我们能提前知道各个Process对于资源的需求情况,我们就可以用Banker's algorithm (银行家算法) 来解决问题.可是这在现在中不好实现,因为很难提前知道 ...
- Kafka系列之-Kafka Protocol实例分析
本文基于A Guide To The Kafka Protocol文档,以及Spark Streaming中实现的org.apache.spark.streaming.kafka.KafkaClust ...
- Protocol Buffer学习笔记
Protocol Buffer Protobuf基础概念 Protobuf是google开发的数据结构描述语言,能够将结构化数据序列化与反序列化,取代json和xml,常用于服务器通信协议.RPC系统 ...
- https那些事儿
(一)SSL/TLS协议运行机制的概述 一.作用 不使用SSL/TLS的HTTP通信,就是不加密的通信.所有信息明文传播,带来了三大风险. (1) 窃听风险(eavesdropping):第三方可以获 ...
随机推荐
- docker-ce的安装以及卸载
注意:以下命令无特殊说明外均在root用户下执行 一.Docker CE的安装 1. 首先,卸载老旧的docker. yum remove docker \ docker-client \ docke ...
- flask接收前台的form数据
转自 http://www.cnblogs.com/wanghaonull/p/6340096.html 我主要是想了解 request.form.get('username') 这一部分
- Java实现BF算法
package 串的算法; public class BF { public static void main(String[] args) { String a = "aaabbaaacc ...
- 2017 最新的 cocoaPods 安装方法
经过努力终于发现了最新的 解决cocoaPods安装的办法: taobao Gems 源已停止维护,现由 ruby-china 提供镜像服务 第一步:安装rvm, 不管需不需要升级ruby,rvm可以 ...
- 编程开发之--java多线程学习总结(3)类锁
2.使用方法同步 package com.lfy.ThreadsSynchronize; /** * 1.使用同步方法 * 语法:即用 synchronized 关键字修饰方法(注意是在1个对象中用锁 ...
- CSS04--对齐、 布局、导航栏
我们接着上一章,继续学习一些有关对齐.布局.导航栏的内容. 1.水平块对齐: 1.1 margin:把左和右外边距设置为 auto,规定的是均等地分配可用的外边距.结果就是居中的元素 .c ...
- 如何在ASP.NET Core 2.0中使用Razor页面
如何在ASP.NET Core 2.0中使用Razor页面 DotNetCore2017-11-22 14:49 问题 如何在ASP.NET Core 2.0中使用Razor页面 解 创建一个空的项 ...
- HQL的使用和limit的替代
1.HQL不同于SQL,from必须是项目中table反转后对应的class的名字. 2.如何使用参数生成HQL语句: String hql = "from User where userI ...
- input[type="file"]上传图片并显示图片
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 【GIS新探索】算法实现在不规则区域内均匀分布点
1 概要 在不规则区域内均匀分布点,这个需求初看可能不好理解.如果设想一下需求场景就比较简单了. 场景1:在某个地区范围内,例如A市区有100W人口,需要将这100W人口在地图上面相对均匀的标识出来. ...