Синхронизация часов малого размера без NTP - PullRequest
13 голосов
/ 13 апреля 2011

Я ищу простой протокол синхронизации часов, который можно было бы легко реализовать с небольшими размерами и который работал бы также при отсутствии подключения к Интернету, чтобы его можно было использовать, например, в закрытых лабораторных сетях. Чтобы было ясно, я не ищу что-то, что можно использовать просто для упорядочения событий (например, векторные часы), а то, что позволило бы процессам на разных узлах синхронизировать свои действия на основе локальных часов. Насколько я понимаю, для этого потребуется решение, которое может учитывать сдвиг часов. Можно предположить наличие TCP / IP или аналогичных потоковых соединений с относительно низкой задержкой.

Ответы [ 6 ]

10 голосов
/ 19 мая 2011

Отказ от ответственности: Я ни в коем случае не эксперт по NTP. Просто любитель веселья на выходных.

Я понимаю, что вы сказали, что вам не нужна реализация NTP из-за предполагаемой сложности и из-за того, что сервер NTP в Интернете может быть недоступен в вашей среде.

Однако упрощенный поиск NTP может быть легко реализован, и если у вас есть локальный NTP-сервер, вы можете добиться хорошей синхронизации.

Вот как:

Отзыв RFC 5905

Вы увидите, что пакеты NTP v4 выглядят примерно так:

  • LI (2 бита)
  • VN (3 бита) - используйте «100» (4)
  • Режим (3 бита)
  • Stratum (8 бит)
  • Опрос (8 бит)
  • Точность (8 бит)
  • Корневая задержка (32 бита)
  • корневая дисперсия (32 бита)
  • Идентификатор ссылки (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 бита. Он представляет количество секунд с 0 ч 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];

Чтобы обновить часы с (примерно) второй степенью детализации, используйте: # секунд с 0 ч. Jan-1-1900 = 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;

"сейчас" теперь DateTime с текущим временем в UTC.

Хотя это может и не ответить на ваш вопрос, надеюсь, это сделает NTP немного менее непрозрачным. =)

5 голосов
/ 19 мая 2011

Мне удалось очень быстро и легко реализовать разборчивую версию протокола Precision Time, основываясь исключительно на статье из Википедии.Если все, что вас интересует, это синхронизировать их друг с другом, а не синхронизировать их с внешним миром, вы должны быть в состоянии получить точность в миллисекунды с минимальными усилиями.

Фундаментальные основы протокола включают следующее:

  1. Основные часы транслируют сообщение синхронизации с отметкой времени, когда он отправил сообщение (T1).
  2. Клиенты записывают время, в которое они получили сообщение синхронизации, как T1 '.
  3. Клиенты отправляют запрос на задержку обратно мастеру и записывают время, когда они отправили сообщение, как T2.
  4. Мастер отвечает на запрос на задержку временем, когда он получил сообщение.Это время T2 '.
  5. Клиент настраивает свои часы с помощью (T1' - T1 - T2 '+ T2) /2.

Если вам нужна лучшая стабильность, вы можете реализоватьфазовая автоподстройка частоты или линейная регрессия или что-то подобное, чтобы лучше контролировать дрожание и избежать больших колебаний из-за сетевых задержекПротокол определяет ряд более сложных функций, но их реализация зависит от того, насколько близко «достаточно хорошо».

2 голосов
/ 19 мая 2011

NTP является правильным инструментом для работы. Вам не нужно подключение к Интернету, и за дополнительные 105 долларов и несколько часов вашей жизни, вы даже можете синхронизироваться с GPS по абсолютному времени без подключения к Интернету, хотя это, кажется, не важно для вас.

Игнорируя небольшую дополнительную сложность синхронизации GPS, вы можете синхронизироваться с часами выбранной системы, используя несколько строк файла конфигурации (четыре строки на каждом клиенте, пять строк на сервере). Двоичный файл ntpd в моей системе составляет 505 КБ. Вы также можете использовать ntpdate, который можно периодически запускать для настройки системных часов (ноль строк конфигурации на клиенте, кроме вызова приложения ntpdate с правильными аргументами). Этот двоичный файл составляет 80 КБ. Существует протокол SNTP, который позволяет использовать встроенные приложения еще меньше (общаясь с обычным ntp-сервером). Существует также альтернативная реализация NTP, которая называется chrony.

Существует также программа под названием rdate (обычно только в старых системах, хотя source доступен), которая работает примерно так же, как ntpdate, но гораздо менее точно. Вам также нужен сервер RFC 868, часто предоставляемый в inetd.

Единственная другая альтернатива - протокол точного времени, уже упомянутый.

2 голосов
/ 14 мая 2011

Может Протокол точного времени соответствует ли счет?Это не выглядит очень просто, но, кажется, делает более или менее точно то, что вы просите.(На странице Википедии есть ссылки на некоторые реализации с открытым исходным кодом.)

Мне кажется, проблема в том, что это сложная проблема, поэтому решения, как правило, сложные.NTP пытается обеспечить правильное абсолютное время, которое определенно выходит за рамки того, что вам нужно, но оно имеет то преимущество, что оно хорошо известно и широко применяется.

0 голосов
/ 20 мая 2011

Не совсем правильный ответ, но просто напоминание, чтобы убедиться, что вы точно понимаете, каковы аппаратные источники тактовых импульсов и какие-либо предостережения о них, особенно если вы планируете использовать некоторые немного экзотические возможности, такие как маломощный ЦПКомбинация RTOS, которую вы упоминаете.

Даже корпус x86 имеет как минимум 2 или 3 тактовых генератора, которые могут использоваться, в зависимости от настройки - все с различными свойствами.

0 голосов
/ 18 мая 2011

Может быть уместно использовать http://www.ietf.org/rfc/rfc5905.txt?

Даже если это намного больше, чем нужно, вы, безусловно, можете реализовать «совместимый» клиент, который работает с NTP-сервером (даже если вызапустить свой собственный NTP-сервер), но где реализация клиента намеренно наивна?

Например, если вам не нужны мелкие корректировки времени, не используйте их.Если вас не волнует двунаправленная синхронизация, не применяйте ее, и так далее.

(Имейте в виду: большинство функций, присутствующих в этом RFC, есть по причине - точная синхронизация времени имеет много подводных камней - в том числетот факт, что многим ОС не нравится, если время внезапно меняется)

...