Подтвердить что ты не робот

Синхронизация с синхронизацией по времени без NTP

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

4b9b3361

Ответ 1

Отказ от ответственности: я не эксперт 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).

Использование С# для иллюстрации:

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 бита. Он представляет количество секунд с 0h по 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];

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

"now" теперь является DateTime с текущим временем в UTC.

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

Ответ 2

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

Основополагающие основы протокола включают следующее:

  • Главный синхросигнал передает сообщение синхронизации с отметкой времени, когда он отправил сообщение (T1).
  • Клиенты записывают время, в которое они получили сообщение синхронизации, как T1 '.
  • Клиенты отправляют запрос на задержку обратно ведущему устройству и записывают время отправки сообщения как T2.
  • Ведущий отвечает на запрос задержки с момента получения сообщения. На этот раз T2 '.
  • Клиент настраивает свои часы на (T1 '- T1 - T2' + T2)/2.

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

Ответ 3

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

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

Ответ 4

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

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

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

Единственная альтернатива - это уже упоминавшийся ранее протокол Precision Time.

Ответ 5

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

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

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

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

Ответ 6

Не совсем правильный ответ, а просто напоминание о том, что вы точно понимаете, что такое источники аппаратных часов и какие-либо оговорки о них, особенно если вы планируете использовать некоторые слегка экзотические возможности, такие как маломощные CPU/RTOS.

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