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获取准确时间的更多相关文章

  1. Java获取NTP网络时间

    最近项目中涉及到一个时间验证的问题,需要根据当前时间来验证业务数据是否过期.所以直接写代码如下: new java.util.Date().getTime();          结果测试的时候出现了 ...

  2. 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 ...

  3. Common Internet File System

    CIFS (Common Internet File System) is a protocol that gained popularity around the year 2000, as ven ...

  4. 【计算机网络】-网络层-Internet的网络层

    [计算机网络]-网络层-Internet的网络层 Internet是一组相互连接的网络或者自治系统的集合 Internet 1.存在几个主要骨干网络,骨干网络是由高带宽的线路和快速路由器构成 2.这些 ...

  5. 《TCP/IP详解卷1:协议》第6章 ICMP:Internet控制报文协议-读书笔记

    章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...

  6. [Database] Deadlock avoidance protocol

    如何避免Deadlock,如果我们能提前知道各个Process对于资源的需求情况,我们就可以用Banker's algorithm (银行家算法) 来解决问题.可是这在现在中不好实现,因为很难提前知道 ...

  7. Kafka系列之-Kafka Protocol实例分析

    本文基于A Guide To The Kafka Protocol文档,以及Spark Streaming中实现的org.apache.spark.streaming.kafka.KafkaClust ...

  8. Protocol Buffer学习笔记

    Protocol Buffer Protobuf基础概念 Protobuf是google开发的数据结构描述语言,能够将结构化数据序列化与反序列化,取代json和xml,常用于服务器通信协议.RPC系统 ...

  9. https那些事儿

    (一)SSL/TLS协议运行机制的概述 一.作用 不使用SSL/TLS的HTTP通信,就是不加密的通信.所有信息明文传播,带来了三大风险. (1) 窃听风险(eavesdropping):第三方可以获 ...

随机推荐

  1. AGC007C Pushing Balls

    题目链接 题意:\(N\)个坑,\(N+1\)个球,相间分布,距离为以\(d_1\)为首项,\(x\)为公差的等差数列.对于每次操作,随机选择一个未入坑的球,随机选择向左或向右,掉入第一个没有球的坑, ...

  2. declare命令

    还是围绕以下几个问题进行学习; 1.declare是什么? 2.问什么要用declare? 3.怎样使用declare? 1.declare是什么? ♦declare应用的很多,向我们各种语言都会有声 ...

  3. leetcode-884-两句话中的不常见单词

    题目描述: 给定两个句子 A 和 B . (句子是一串由空格分隔的单词.每个单词仅由小写字母组成.) 如果一个单词在其中一个句子中只出现一次,在另一个句子中却没有出现,那么这个单词就是不常见的. 返回 ...

  4. Django中的Cookie--实现登录

    Django中的Cookie--实现登录 Django Cookie  Cookie Cookie 是什么 保存在浏览器端的键值对,让服务器提取有用的信息. 为什么要有 Cookie 因为HTTP请求 ...

  5. 2018南京网络赛 - Skr 回文树

    题意:求本质不同的回文串(大整数)的数字和 由回文树的性质可知贡献只在首次进入某个新节点时产生 那么只需由pos和len算出距离把左边右边删掉再算好base重复\(O(n)\)次即可 位移那段写的略微 ...

  6. 编写一个算法,将非负的十进制整数转换为其他进制的数输出,10及其以上的数字从‘A’开始的字母表示

    编写一个算法,将非负的十进制整数转换为其他进制的数输出,10及其以上的数字从‘A’开始的字母表示. 要求: 1) 采用顺序栈实现算法: 2)从键盘输入一个十进制的数,输出相应的八进制数和十六进制数. ...

  7. Redis报错:redis.exceptions.ResponseError: MISCONF Redis is configured to save RDB snap

    首先找到出现错误的原因: redis.exceptions.ResponseError: MISCONF Redis is configured to save RDB snapshots, but ...

  8. [Xamarin] 透過StartActivityForResult傳值回來(转贴)

    上一篇文章(開啟另外一個Activity 並且帶資料),提到了開啟一個新的Activity ,我們將值透過intent 帶到下個Activity 但是,如果我們開啟的Actrivity其實是有一個任務 ...

  9. 【Ubuntu】命令记录

    cp 该命令的功能是将给出的文件或目录拷贝到另一文件或目录中,就如同DOS下的copy命令一样,功能非常强大. 语法: cp [选项] 源文件或目录 目标文件或目录 说明:该命令把指定的源文件复制到目 ...

  10. 【Druid】access denied for user ''@'ip'

    今天在写单元测试时,遇到一个很奇葩的问题,一直在报这样的错误: Caused by: java.sql.SQLException: Access denied for user ''@'183.134 ...