无需 NTP 即可实现小规模时钟同步

发布于 2024-11-01 05:58:23 字数 193 浏览 1 评论 0原文

我正在寻找一种简单的时钟同步协议,该协议易于实现,占用空间小,并且在没有互联网连接的情况下也可以工作,以便它可以在封闭的实验室网络中使用。需要明确的是,我并不是在寻找仅可用于排序事件的东西(例如矢量时钟),而是在寻找使不同节点上的进程能够根据本地时钟同步其操作的东西。据我了解,这需要一个可以考虑时钟漂移的解决方案。可以假设存在 TCP/IP 或类似的相对低延迟的流连接。

I'm looking for a simple clock synchronization protocol that would be easy to implement with small footprint and that would work also in the absence of internet connection, so that it could be used e.g. within closed laboratory networks. To be clear, I'm not looking for something that can be used just to order events (like vector clocks), but something that would enable processes on different nodes to synchronize their actions based on local clocks. As far as I understand, this would require a solution that can take clock drift into account. Presence of TCP/IP or similar relatively low-latency stream connections can be assumed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

不必你懂 2024-11-08 05:58:23

免责声明:无论如何我都不是 NTP 专家。只是一个周末玩得开心的业余爱好者。

我知道您说过您不想要 NTP 实施,因为您认为很复杂,而且您的环境中可能无法使用 Internet NTP 服务器。

但是,简化的 NTP 查找可能很容易实现,并且如果您有本地 NTP 服务器,则可以实现良好的同步。

操作方法如下:

查看 RFC 5905

您会看到 NTP v4 数据包如下所示:

  • LI (2 位)
  • VN (3 位) - 使用“100” (4)
  • 模式 (3 位)
  • 层 (8 位)
  • 轮询 (8 位)
  • 精度 (8 位)
  • 根延迟 (32 位)
  • 根分散 (32 位)
  • 参考Id(32 位)
  • 参考时间戳(64 位)
  • 源时间戳(64 位)
  • 接收时间戳(64 位)
  • 传输时间戳(64 位)
  • 扩展字段 1(变量)
  • 扩展字段 2(变量)
  • ...
  • 密钥标识符
  • 摘要(128 位) )

不需要摘要,因此形成有效的客户端请求非常容易。按照 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

打开一个到目标服务器的套接字并将其发送过来。

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);

在响应中,当前时间将位于传输时间戳(字节 [40 - 48])中。时间戳是 64 位无符号定点数。整数部分是前32位,小数部分是后32位。它表示从 1900 年 1 月 1 日 0 点开始的秒数。

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];

要以(大致)秒粒度更新时钟,请使用:自 1900 年 1 月 1 日 0 点以来的秒数 = 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;

“now”现在是一个包含当前时间的 DateTime(UTC 时间)。

虽然这可能无法回答您的问题,但希望它能让 NTP 不那么不透明。 =)

Disclaimer: I'm not an NTP expert by any means. Just a hobbyist having fun on the weekend.

I realize you said you didn't want an NTP implementation, because of the perceived complexity and because an Internet NTP server may not be available in your environment.

However, an simplified NTP look-up may be easy to implement, and if you have a local NTP server you can achieve good synchronization.

Here's how:

Review RFC 5905

You'll see NTP v4 packets look something like:

  • LI (2 bits)
  • VN (3 bits) - Use '100' (4)
  • Mode (3 bits)
  • Stratum (8 bits)
  • Poll (8 bits)
  • Precision (8 bits)
  • Root Delay (32 bits)
  • Root Dispersion (32 bits)
  • Reference Id (32 bits)
  • Reference Timestamp (64 bits)
  • Origin Timestamp (64 bits)
  • Receive Timestamp (64 bits)
  • Transmit Timestamp (64 bits)
  • Extension Field 1 (variable)
  • Extension Field 2 (variable)
  • ...
  • Key Identifier
  • Digest (128 bits)

The digest is not required, so forming a valid client request is very easy. Following the guidance in the RFC, use LI = '00', VN = '100' (decimal 4), Mode = '011' (decimal 3).

Using C# to illustrate:

byte[] ntpData = new byte[48]
Array.Clear(ntpData, 0, ntpData.Length);
ntpData[0] = 0x23;  // LI = 00, VN = 100, Mode = 011

Open a socket to your target server and send it over.

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);

In the response, the current time will be in the Transmit Timestamp (bytes [40 - 48]). Timestamps are 64-bit unsigned fixed-point numbers. The integer part is the first 32 bits, the fractional part is the last 32 bits. It represents the number of seconds since 0h on Jan-1-1900.

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];

To update the clock with (roughly) second granularity, use: # of seconds since 0h Jan-1-1900 = intPart + (fractPart / 2^32). (I say roughly because network latency isn't accounted for, and we're rounding down here)

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;

"now" is now a DateTime with the current time, in UTC.

While this might not answer your question, hopefully it makes NTP a little less opaque. =)

﹉夏雨初晴づ 2024-11-08 05:58:23

仅根据维基百科文章,我就能够非常快速且轻松地实现精确时间协议的简化版本。如果您感兴趣的是使它们相互同步而不是与外界同步,那么您应该能够以最小的努力获得毫秒精度。

该协议的基本原理如下:

  1. 主时钟广播一条同步消息,其中包含发送消息时的时间戳 (T1)。
  2. 客户端将收到同步消息的时间记录为 T1'。
  3. 客户端将延迟请求发送回主服务器,并将发送消息的时间记录为 T2。
  4. 主站以收到消息的时间响应延迟请求。这次是T2'。
  5. 客户端将时钟调整为 (T1' - T1 - T2' + T2)/2。

如果您需要更好的稳定性,您可以实现锁相环或线性回归或类似的东西,以更好地控制抖动并避免由于网络滞后而导致的大幅波动。协议指定了许多更复杂的功能,但是否要实现它们取决于“足够好”的程度。

I was able to implement a parred down version of the Precision Time Protocol very quickly and easily based solely on the wikipedia article. If all you are interested in is synchronizing them with each other as opposed to synchronizing them with the outside world, you should be able to get millisecond accuracy with minimal effort.

The fundamental basics of the protocol involve the following:

  1. A master clock broadcasts a sync message with the timestamp of when he sent the message (T1).
  2. The clients record the time at which they received the sync message as T1'.
  3. The clients send a delay request back to the master and record the time they sent the message as T2.
  4. The master responds to the delay request with the time he received the message. This time is T2'.
  5. Client adjusts their clock by (T1' - T1 - T2' + T2)/2.

If you need better stability, you can implement a phase locked loop or a linear regression or something similar to better control your jitter and avoid large swings due to network lags. There are a number of more complicated features specified by the protocol, but if you want to implement them depends on how close 'good enough' is.

━╋う一瞬間旳綻放 2024-11-08 05:58:23

ntp 是完成这项工作的正确工具。你不需要互联网连接,只要额外支付 105 美元和你生命中的几个小时,你甚至可以在没有互联网连接的情况下进行 GPS 同步以获得绝对时间参考,尽管这对你来说似乎并不重要。

忽略 GPS 同步稍微增加的复杂性,您可以使用几行配置文件(每个客户端上四行,服务器上五行)来同步到所选系统的时钟。我的系统上的 ntpd 二进制文件大小为 505kB。您还可以使用 ntpdate,它可以定期运行来调整系统时钟(客户端上的零行配置,而不是使用正确的参数调用 ntpdate 应用程序)。该二进制文件大小为 80kb。有一个 SNTP 协议,它允许嵌入式应用程序占用更小的空间(与普通的 ntp 服务器通信)。还有一种称为 chrony 的替代 NTP 实现。

还有一个名为 rdate 的程序(通常仅在较旧的系统上,尽管是可用),其工作方式有点像 ntpdate,但不太精确。您还需要一个 RFC 868 服务器,通常在 inetd 中提供。

唯一的其他选择是已经提到的精确时间协议。

ntp is the right tool for the job. You do not need an internet connection, and for an extra $105 and a few hours of your life, you can even be GPS synchronized for an absolute time reference without an internet connection, though that appears to not be important to you.

Ignoring the slight additional complexity of GPS synchronization, you can get synchronized to a chosen system's clock using a few configuration file lines (four lines on each client, five lines on the server). The ntpd binary is 505kB on my system. You can also use ntpdate which can be periodically run to adjust the system clock (zero lines of configuration on the client, other than the call to the ntpdate application with the right arguments). That binary is 80kb. There is a SNTP protocol which allows even smaller footprints for embedded appliations (talking to a normal ntp server). There is also an alternate NTP implementation called chrony.

There is also a program called rdate (typically only on older systems, though source is available) which works kinda like ntpdate but much less precisely. You also need an RFC 868 server, often provided in inetd.

The only other alternative is the Precision Time Protocol already mentioned.

野稚 2024-11-08 05:58:23

精确时间协议可能符合要求吗?它看起来并不简单,但它似乎或多或少完全符合您的要求。 (维基百科页面上引用了一些开源实现。)

我认为问题在于这本质上是一个棘手的问题,因此解决方案往往很复杂。 NTP 试图提供正确的绝对时间,这肯定超出了您的需要,但它确实具有众所周知且广泛实施的优势。

Might Precision Time Protocol fit the bill? It doesn't look real simple, but it seems to do more or less exactly what you are asking for. (There are some open source implementations referenced on the Wikipedia page.)

I think the problem is that this is an inherently tricky problem, so the solutions tend to be complex. NTP is trying to provide a correct absolute time, which definitely goes beyond what you need, but it does have the advantage of being well known and widely implemented.

莫言歌 2024-11-08 05:58:23

可能使用 http://www.ietf.org/rfc/rfc5905.txt 合适?

即使它比您需要的多得多,您当然可以实现一个与 NTP 服务器一起使用的“兼容”客户端(即使您运行自己的 NTP 服务器),但是客户端实现是故意幼稚的吗?

例如,如果您不关心小的时间调整,就不要实施它们。如果您不关心双向同步,请不要实现它,等等。

(请注意:RFC 中存在的大多数功能都是有原因的 - 准确的时间同步有很多陷阱 - 包括许多操作系统不喜欢时间突然变化的事实)

Might using http://www.ietf.org/rfc/rfc5905.txt be appropriate?

Even if it is much more than what you need, you could certainly implement a "compatible" client that works with an NTP server (even if you run your own NTP server), but where the client implementation is purposely naive?

Eg, if you don't care about small time adjustments, don't implement them. If you don't care about bidirectional synchronisation, don't implement that, etcetera.

(Be warned: Most of the functionality present in that RFC is there for a reason - Accurate time synchronisation has many pitfalls - including the fact that many OS's do not like it if the time suddenly changes)

若水般的淡然安静女子 2024-11-08 05:58:23

这并不是一个真正正确的答案,只是提醒您确保您准确了解硬件时钟源是什么以及有关它们的任何注意事项 - 特别是如果您计划使用一些稍微奇特的可能性,例如您的低功耗 CPU / RTOS 组合提到。

即使 x86 机箱也至少有 2 或 3 个可以使用的时钟,具体取决于设置 - 全部具有不同的属性。

Not really a proper answer, but just a reminder to make sure that you understand exactly what the hardware clock sources are and any caveats about them - especially if you are planning to use some slightly exotic possibilities like the low-power CPU / RTOS combination you mention.

Even the x86 case has at least 2 or 3 clocks which could be in use, depending on the setup - all with different properties.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文