最近发现手机的时间不是很准了,便到网上下了一个同步时间的小程序,简单了看了一下它的原理,是通过NTP协议来实现校时的,就顺便学习了一下NTP协议,用C#写了个简单的实现。

NTP(Network Time Protocol,网络时间协议)是由RFC 1305定义的时间同步协议,用来在分布式时间服务器和客户端之间进行时间同步。

NTP工作原理

NTP的基本工作原理如下图所示。Device A和Device B通过网络相连,它们都有自己独立的系统时钟,需要通过NTP实现各自系统时钟的自动同步。为便于理解,作如下假设:

  • 在Device A和Device B的系统时钟同步之前,Device A的时钟设定为10:00:00am,Device B的时钟设定为11:00:00am。
  • Device B作为NTP时间服务器,即Device A将使自己的时钟与Device B的时钟同步。
  • NTP报文在Device A和Device B之间单向传输所需要的时间为1秒。

  • Device A发送一个NTP报文给Device B,该报文带有它离开Device A时的时间戳,该时间戳为10:00:00am(T1)。
  • 当此NTP报文到达Device B时,Device B加上自己的时间戳,该时间戳为11:00:01am(T2)。
  • 当此NTP报文离开Device B时,Device B再加上自己的时间戳,该时间戳为11:00:02am(T3)。
  • 当Device A接收到该响应报文时,Device A的本地时间为10:00:03am(T4)。

至此,Device A已经拥有足够的信息来计算两个重要的参数:

  • NTP报文的往返时延Delay=(T4-T1)-(T3-T2)=2秒。
  • Device A相对Device B的时间差offset=((T2-T1)+(T3-T4))/2=1小时。

NTP的报文格式

NTP有两种不同类型的报文,一种是时钟同步报文,另一种是控制报文(仅用于需要网络管理的场合,与本文无关,这里不做介绍)。

NTP基于UDP报文进行传输,使用的UDP端口号为123;时钟同步报文封装在UDP报文中,其格式如下图所示。

主要字段的解释如下:

  • LI(Leap Indicator):长度为2比特,值为“11”时表示告警状态,时钟未被同步。为其他值时NTP本身不做处理。
  • VN(Version Number):长度为3比特,表示NTP的版本号,目前的最新版本为3。
  • Mode:长度为3比特,表示NTP的工作模式。不同的值所表示的含义分别是:0未定义、1表示主动对等体模式、2表示被动对等体模式、3表示客户模式、4表示服务器模式、5表示广播模式或组播模式、6表示此报文为NTP控制报文、7预留给内部使用。
  • Stratum:系统时钟的层数,取值范围为1~16,它定义了时钟的准确度。层数为1的时钟准确度最高,准确度从1到16依次递减,层数为16的时钟处于未同步状态,不能作为参考时钟。
  • Poll:轮询时间,即两个连续NTP报文之间的时间间隔。
  • Precision:系统时钟的精度。
  • Root Delay:本地到主参考时钟源的往返时间。
  • Root Dispersion:系统时钟相对于主参考时钟的最大误差。
  • Reference Identifier:参考时钟源的标识。
  • Reference Timestamp:系统时钟最后一次被设定或更新的时间。
  • Originate Timestamp:NTP请求报文离开发送端时发送端的本地时间。
  • Receive Timestamp:NTP请求报文到达接收端时接收端的本地时间。
  • Transmit Timestamp:应答报文离开应答者时应答者的本地时间。
  • Authenticator:验证信息。

NTP时间同步的实现

有了上述基础知识后,我们就可以实现自己的时间同步工具了,下文附了一个简单的C#的实现。

class NptClient

{

IPAddress ntpServer;

public NptClient(IPAddress ntpServer)

{

this.ntpServer = ntpServer;

}

public DateTime GetServerTime()

{

var startTime = DateTime.Now;

var ntpTime = NTPData.Test(ntpServer);

var recvTime = DateTime.Now;

var offset = ((ntpTime.ReceiveTimestamp - startTime) + (ntpTime.TransmitTimestamp - recvTime));

offset = offset.Subtract(TimeSpan.FromSeconds(offset.TotalSeconds / 2));

return recvTime + offset;

}

}

[StructLayout(LayoutKind.Sequential)]

class NTPData

{

byte header = 0;

byte Stratum = 1;           //系统时钟的层数,取值范围为1~16,它定义了时钟的准确度

byte Poll = 1;              //轮询时间,即两个连续NTP报文之间的时间间隔

byte Precision = 1;         //系统时钟的精度

BigEndianUInt32 rootDelay;

BigEndianUInt32 referenceIdentifier;

BigEndianUInt32 ReferenceIdentifier;

public NtpTime ReferenceTimestamp { get; private set; }

public NtpTime OriginateTimestamp { get; private set; }

public NtpTime ReceiveTimestamp { get; private set; }

public NtpTime TransmitTimestamp { get; private set; }

public NTPData()

{

this.header = GetHeader();

}

byte GetHeader()

{

var LI = "00";

var VN = "011";         //NTP的版本号为3

var Mode = "011";       //客户模式

return Convert.ToByte(LI + VN + Mode, 2);

}

public static NTPData Test(IPAddress ntpServer)

{

var data = MarshalExtend.GetData(new NTPData());

var udp = new System.Net.Sockets.UdpClient();

udp.Send(data, data.Length, new IPEndPoint(ntpServer, 123));

var ep = new IPEndPoint(IPAddress.Any, 0);

var replyData = udp.Receive(ref ep);

return MarshalExtend.GetStruct<NTPData>(replyData, replyData.Length);

}

}

[StructLayout(LayoutKind.Sequential)]

class NtpTime

{

BigEndianUInt32 seconds;

BigEndianUInt32 fraction;

static readonly DateTime baseTime = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc);

public static implicit operator DateTime(NtpTime time)

{

/* rfc1305的ntp时间中,时间是用64bit来表示的,记录的是1900年后的秒数(utc格式)

* 高32位是整数部分,低32位是小数部分 */

var milliseconds = (int)(((double)time.fraction / uint.MaxValue) * 1000);

return baseTime.AddSeconds(time.seconds).AddMilliseconds(milliseconds).ToLocalTime();

}

public override string ToString()

{

return ((DateTime)this).ToString("o");

}

}

当然,我这里只是在造重复轮子,网上是有不少功能完整的开源项目的。另外,如果对SNTPv4(RFC 2030)感兴趣的,可以参考一下这个页面上的实现——Simple Network Time (NTP) Protocol Client

最后,附上几个可以使用(不保证,具体能用否还得看电信和方校长的心情)的NTP服务器:

  • 133.100.11.8 prefer
  • 210.72.145.44
  • 203.117.180.36
  • 131.107.1.10
  • time.asia.apple.com
  • 64.236.96.53
  • 130.149.17.21
  • 66.92.68.246
  • 18.145.0.30
  • clock.via.net
  • 137.92.140.80
  • 133.100.9.2
  • 128.118.46.3
  • ntp.nasa.gov
  • 129.7.1.66ntp-sop.inria.frserver
  • 210.72.145.44(中国国家授时中心服务器IP地址)
  • ntp.sjtu.edu.cn (上海交通大学网络中心NTP服务器地址)
  • 202.120.2.101 (上海交通大学网络中心NTP服务器地址)

通过NTP协议进行时间同步的更多相关文章

  1. 使用NTP协议服务器时间同步

    NTP是用来使系统和一个精确的时间源保持时间同步的协议.建议大家在自己管理的网络中建立至少一台时间服务器来同步本地时间,这样可以使得在不同的系统上处理和收集日志和管理更加容易.我们分别从windows ...

  2. golang ntp协议客户端

    NTP(Network Time Protocol,网络时间协议)是由RFC 1305定义的时间同步协议,用来在分布式时间服务器和客户端之间进行时间同步.NTP基于UDP报文进行传输,使用的UDP端口 ...

  3. 部署NTP服务器进行时间同步

    NTP服务端:linl_S    IP:10.0.0.15 NTP客户端:lin_C    IP:10.0.0.16 NTP服务概述 1.原理 NTP(Network TimeProtocol,网络时 ...

  4. 实现基于NTP协议的网络校时功能

    无论PC端还是移动端系统都自带时间同步功能,基于的都是NTP协议,这里使用C#来实现基于NTP协议的网络校时功能(也就是实现时间同步). 1.NTP原理 NTP[Network Time Protoc ...

  5. NTP 协议介绍

    NTP协议 NTP(Network Time Protocol,网络时间协议)是由RFC 1305定义的时间同步协议,用来在分布式时间服务器和客户端之间进行时间同步.NTP基于UDP报文进行传输,使用 ...

  6. ntp时间服务器 时间同步

    具体两种模式 1.服务器数量比较少,可以直接与时间服务器同步 2.本地服务器较多,在本地自建时间同步服务器,     时间同步的两个命令 ntpd :         校准时间,一点点的校准过来时间的 ...

  7. linux服务之NTP及chrony时间同步

    博客园 首页 联系 管理   linux服务之NTP及chrony时间同步   一.NTP时间同步 NTP(Network Time Protocol,网络时间协议)是由RFC 1305定义的时间同步 ...

  8. 使用ntp协议同步本地时间(C语言)

    使用ntp协议同步本地时间 同步服务器使用的东北大学网络授时服务:ntp.neu.edu.cn更多ntp服务器 http://www.ntp.org.cn/ 源代码来自网络,经本人精简ntp部分,供大 ...

  9. CentOS 7.2部署NTP服务器实现时间同步

    CentOS 7.2部署NTP服务器实现时间同步 [日期:2017-12-18] 来源:Linux社区  作者:梁明远 [字体:大 中 小]   1. 前言 对于容器编排系统,前段时间主要研究kube ...

随机推荐

  1. [WC2008]游览计划 「斯坦那树模板」

    斯坦那树 百度释义 斯坦纳树问题是组合优化问题,与最小生成树相似,是最短网络的一种.最小生成树是在给定的点集和边中寻求最短网络使所有点连通.而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开 ...

  2. Oracle学习笔记:a inner join b与from a,b where a.x=b.x的差异

    近期,在使用Oracle的过程中,由以下两段代码的执行引发的思考,到底 select * from a,b where a.id = b.id 和 select * from a inner join ...

  3. MVC4是不是类似于html页+ashx页之间用JSON通过AJAX交换数据这种方式、?

    不是,可以讲mvc模式是借鉴于java下面的mvc开发模式,为开发者公开了更多的内容和控制,更易于分工合作,与单元测试,借用官方的说法:MVC (Model.View.Controller)将一个We ...

  4. 用ProFTPD构建FTP服务器

    配置 ProFTPD 然后,通过修改相应配置文件配置ProFTPD. [root@sample ~]# vi /etc/proftpd.conf ← 修改ProFTPD的配置文件 ServerType ...

  5. chisequre test

    卡方检验就是统计样本的实际观测值与理论推断值之间的偏离程度,实际观测值与理论推断值之间的偏离程度就决定卡方值的大小,卡方值越大,越不符合:卡方值越小,偏差越小,越趋于符合,若两个值完全相等时,卡方值就 ...

  6. 系统管理员常用的Linux命令

    整理Linux的一些基本系统管理命令作为备忘 ========================================================================= 查看文 ...

  7. Wannafly 挑战赛 19 参考题解

    这一次的 Wannafly 挑战赛题目是我出的,除了第一题,剩余的题目好像对大部分算法竞赛者来说好像都不是特别友好,但是个人感觉题目质量还是过得去的,下面是题目链接以及题解. [题目链接] Wanna ...

  8. [ 转载 ] Http详解2

    HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统 | |目录 1引言 2一.HTTP协议详解之URL篇 3二.HTTP协议详解之请求篇 4三.HTTP协议详 ...

  9. Go面试题精编100题

    Golang精编100题 选择题 1.   [初级]下面属于关键字的是()A. funcB. defC. structD. class 参考答案:AC 2.   [初级]定义一个包内全局字符串变量,下 ...

  10. 8.8 正睿暑期集训营 Day5

    目录 2018.8.8 正睿暑期集训营 Day5 总结 A 友谊巨轮(线段树 动态开点) B 璀璨光滑 C 构解巨树 考试代码 A B C 2018.8.8 正睿暑期集训营 Day5 时间:3.5h( ...