Как правило, для реализации часов в вычислительных устройствах используются арифметические счётчики, последовательно увеличивающие хранимое значение с заданной периодичностью. Для определения длительности какого-либо процесса запоминаются значения счётчика в моменты его начала и окончания. Затем из второго значения вычитается первое, получается длительность процесса.
Чтобы определить текущее время при помощи такого счётчика, необходимо знать, что для него является «нулём» или точкой отсчёта. В шкалах времени точки начала отсчёта обычно именуются «эпохами» или «эрами» – вы наверняка слышали про «нашу эру» или, например, эпоху UNIX (система отсчёта времени, принятая в UNIX и других POSIX-совместимых операционных системах с моментом начала отсчёта в полночь с 31 декабря 1969 года на 1 января 1970 по UTC). Точкой отсчёта для протокола NTP является 00 часов 00 минут 1-го января 1900 года.
Момент времени, в который произошло какое-либо событие (т. н. «отпечаток времени», timestamp) в протоколе NTP представляется 64-битным числом без знака с фиксированной точкой. Первые 32 бита представляют собой целое количество секунд, прошедших от начала эпохи, остальные 32 бита – дробную часть. Нетрудно посчитать, что теоретическая точность фиксации событий при этом должна составлять чуть более 200 пикосекунд. Об этом очень красноречиво говорится в RFC, описывающем протокол NTP: «точность этого представления будет достаточна даже для самых экзотических требований».
На практике, конечно же, такая точность не достигается. Обычно все операции в процессорах производятся в моменты событий, называемых прерываниями. Один из видов прерываний вызывается тактовым генератором. Сейчас повсеместно для оборудования общего назначения тактовые генераторы выполняются на основе кварцевых резонаторов, имеющих частоту от нескольких кГц до сотен МГц. Однако, если обновлять значение счётчика с частотой 100 МГц, будет получено разрешение «всего» 10 нс. Кроме того, процессору необходимо обрабатывать и другие задания, плюс на стабильность кварцевого генератора значительно влияют колебания напряжения, температуры и процесс старения кристалла кварца. Поэтому в обычных системах даже такая точность не достигается. Например, модель часов в UNIX «тикает» 1 раз в микросекунду.
При хранении значений с фиксированной разрядностью, важно знать максимальное значение, которое может быть достигнуто, после чего счётчик обнулится. Помните про пресловутую «проблему 2000-го года»? А про проблему 2038 года для 32-разрядных UNIX-подобных систем? У NTP текущей версии тоже есть такая «проблема» – 32 бита для представления целых секунд будут исчерпаны 7 февраля 2036 года.
В NTP время предается от одной системы к другой с использованием сетевого протокола UDP. Сервер, получающий значение времени от эталонного источника (атомных часов или, что наиболее распространено – приёмника сигналов навигационных спутниковых систем), называется сервером первого стратума. Сервер, синхронизированный с сервером первого стратума, будет являться сервером второго стратума, и так далее – стратум системы на единицу больше значения стратума её источника синхронизации.
Процесс синхронизации заключается в пересылке между системами нескольких пакетов данных небольшого размера в виде запросов и ответов на них.
Для вычисления смещения времени между системами и периода, прошедшего от момента отправки запроса до получения ответа на него (задержки), в пересылаемых пакетах используются три поля:
- локальное время клиента в момент отправки запроса
- локальное время сервера в момент приёма запроса
- локальное время сервера в момент отправки ответа
В обычном режиме первый пакет отправляется клиентом. Непосредственно перед отправкой клиент записывает своё текущее время (метка времени t1) и запоминает это значение в переменной.
При получении пакета клиента, сервер формирует ответный пакет. В него копируется значение времени отправки из полученного запроса, и записывается текущее время сервера (метка времени t2, момент получения запроса). После завершения обработки запроса, сервер проставляет в отправляемый пакет своё текущее время (метка времени t3, момент отправки ответа) и отсылает его клиенту.
При получении ответа клиент записывает время его получения (метка времени t4). Теперь у клиента достаточно данных для расчёта значений смещения и задержки, вызванной передачей пакетов в сетевой среде. Однако, перед началом обработки данных производится их проверка, позволяющая исключить обработку продублированных, поддельных или воспроизведённых пакетов.
Смещение времени (разница между временем сервера и клиента) вычисляется как:
Θ = T(B) − T(A) = ½ * [(t2−t1) + (t3−t4)]
, а общее время передачи данных:
Δ = T(ABA) = (t4−t1) − (t3−t2)
Как говорилось выше, передаваемые метки времени представлены 64-битными числами без знака. Для выполнения арифметических операций потребуется выделить один бит под знак – для числа остаётся 63 бита. В расчётах используются суммы и разности этих значений, поэтому необходимо выделить ещё один бит для знака, и под число остаётся 62 бита. Максимальное значение периода времени, которое можно представить таким числом – это примерно 34 года в будущем и 34 года в прошлом. Поэтому, для синхронизации время клиента должно отличаться от времени сервера не более чем на ± 34 года.
При расчётах делается предположение, что сетевая среда симметрична и время задержки, необходимое для отправки и получения данных одинаково. Однако, сетевая среда не идеальна, и это время может различаться. Поэтому при анализе рассчитанных данных используется математическая и статистическая обработка, позволяющая учесть нестабильность сети. Синхронизация с использованием протокола NTP 4-й версии позволяет достигать точности порядка 10 мс для систем, синхронизируемых через Интернет. При синхронизации в локальной сети точность достигает десятых и сотых долей миллисекунд.