Ant*_*ima 14 ip networking distributed synchronization clock
我正在寻找一种简单的时钟同步协议,该协议易于实现,占用空间小,并且在没有互联网连接的情况下也可以工作,因此可以在封闭的实验室网络中使用.为了清楚起见,我不是在寻找可以仅用于命令事件(例如矢量时钟)的东西,而是能够使不同节点上的进程基于本地时钟同步其动作的东西.据我了解,这需要一个可以考虑时钟漂移的解决方案.可以假设存在TCP/IP或类似的相对低延迟的流连接.
Tai*_*ils 11
免责声明:无论如何,我不是NTP专家.只是一个在周末玩乐的爱好者.
我意识到你说你不想要NTP实现,因为感知复杂性,并且因为你的环境中可能没有Internet NTP服务器.
但是,简化的NTP查找可能很容易实现,如果您有本地NTP服务器,则可以实现良好的同步.
这是如何做:
查看RFC 5905
你会看到NTP v4数据包看起来像:
摘要不是必需的,因此形成有效的客户端请求非常容易.遵循RFC中的指导,使用LI = '00',VN ='100'(十进制4),Mode ='011'(十进制3).
使用C#来说明:
byte[] ntpData = new byte[48]
Array.Clear(ntpData, 0, ntpData.Length);
ntpData[0] = 0x23; // LI = 00, VN = 100, Mode = 011
Run Code Online (Sandbox Code Playgroud)
打开目标服务器的套接字并将其发送出去.
int ntpPort = 123;
IPEndPoint target = new IPEndPoint(Dns.GetHostEntry(serverDnsName).AddressList[0], ntpPort);
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
s.Connect(target);
s.Send(ntpData);
Run Code Online (Sandbox Code Playgroud)
在响应中,当前时间将在发送时间戳(字节[40 - 48])中.时间戳是64位无符号定点数.整数部分是前32位,小数部分是最后32位.它表示从1月1日到1月1日0h以来的秒数.
s.Receive(ntpData);
s.Close();
ulong intPart = 0;
ulong fractPart = 0;
for (int i = 0; i < 4; i++)
intPart = (intPart << 8) | ntpData[40 + i];
for (int i = 4; i < 8; i++)
fractPart = (fractPart << 8) | ntpData[40 + i];
Run Code Online (Sandbox Code Playgroud)
要使用(大致)第二粒度更新时钟,请使用:自1月1日1月1日起的秒数= intPart +(fractPart/2 ^ 32).(我粗略地说,因为没有计算网络延迟,我们在这里四舍五入)
ulong seconds = intPart + (fractPart / 4294967296);
TimeSpan ts = TimeSpan.FromTicks((long)seconds * TimeSpan.TicksPerSecond);
DateTime now = new DateTime(1900, 1, 1);
now = DateTime.SpecifyKind(now, DateTimeKind.Utc);
now += ts;
Run Code Online (Sandbox Code Playgroud)
"now"现在是具有当前时间的DateTime,以UTC为单位.
虽然这可能无法解答您的问题,但希望它能使NTP变得不那么透明.=)
我能够基于维基百科文章快速,轻松地实现精确时间协议的精简版本.如果您感兴趣的是将它们彼此同步而不是将它们与外部世界同步,那么您应该能够以最小的努力获得毫秒精度.
该协议的基本基础涉及以下内容:
如果你需要更好的稳定性,你可以实现一个锁相环或线性回归或类似的东西,以更好地控制你的抖动,避免由于网络滞后造成的大幅波动.协议指定了许多更复杂的功能,但是如果要实现它们取决于"足够好"的接近程度.