根据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):第三方可以获 ...
随机推荐
- AGC007C Pushing Balls
题目链接 题意:\(N\)个坑,\(N+1\)个球,相间分布,距离为以\(d_1\)为首项,\(x\)为公差的等差数列.对于每次操作,随机选择一个未入坑的球,随机选择向左或向右,掉入第一个没有球的坑, ...
- declare命令
还是围绕以下几个问题进行学习; 1.declare是什么? 2.问什么要用declare? 3.怎样使用declare? 1.declare是什么? ♦declare应用的很多,向我们各种语言都会有声 ...
- leetcode-884-两句话中的不常见单词
题目描述: 给定两个句子 A 和 B . (句子是一串由空格分隔的单词.每个单词仅由小写字母组成.) 如果一个单词在其中一个句子中只出现一次,在另一个句子中却没有出现,那么这个单词就是不常见的. 返回 ...
- Django中的Cookie--实现登录
Django中的Cookie--实现登录 Django Cookie Cookie Cookie 是什么 保存在浏览器端的键值对,让服务器提取有用的信息. 为什么要有 Cookie 因为HTTP请求 ...
- 2018南京网络赛 - Skr 回文树
题意:求本质不同的回文串(大整数)的数字和 由回文树的性质可知贡献只在首次进入某个新节点时产生 那么只需由pos和len算出距离把左边右边删掉再算好base重复\(O(n)\)次即可 位移那段写的略微 ...
- 编写一个算法,将非负的十进制整数转换为其他进制的数输出,10及其以上的数字从‘A’开始的字母表示
编写一个算法,将非负的十进制整数转换为其他进制的数输出,10及其以上的数字从‘A’开始的字母表示. 要求: 1) 采用顺序栈实现算法: 2)从键盘输入一个十进制的数,输出相应的八进制数和十六进制数. ...
- Redis报错:redis.exceptions.ResponseError: MISCONF Redis is configured to save RDB snap
首先找到出现错误的原因: redis.exceptions.ResponseError: MISCONF Redis is configured to save RDB snapshots, but ...
- [Xamarin] 透過StartActivityForResult傳值回來(转贴)
上一篇文章(開啟另外一個Activity 並且帶資料),提到了開啟一個新的Activity ,我們將值透過intent 帶到下個Activity 但是,如果我們開啟的Actrivity其實是有一個任務 ...
- 【Ubuntu】命令记录
cp 该命令的功能是将给出的文件或目录拷贝到另一文件或目录中,就如同DOS下的copy命令一样,功能非常强大. 语法: cp [选项] 源文件或目录 目标文件或目录 说明:该命令把指定的源文件复制到目 ...
- 【Druid】access denied for user ''@'ip'
今天在写单元测试时,遇到一个很奇葩的问题,一直在报这样的错误: Caused by: java.sql.SQLException: Access denied for user ''@'183.134 ...