Вход/Регистрация
UNIX: разработка сетевых приложений
вернуться

Стивенс Уильям Ричард

Шрифт:

Наша функция

sntp_proc
, показанная в листинге 21.13, обрабатывает пакет NTP.

Листинг 21.13. Функция sntp_proc: обработка пакета NTР

//ssntp/sntp_proc.c

1 #include "sntp.h"

2 void

3 sntp proc(char *buf, ssize_t n, struct timeval *nowptr)

4 {

5 int version, mode;

6 uint32_t nsec, useci;

7 double usecf;

8 struct timeval diff;

9 struct ntpdata *ntp;

10 if (n < (ssize_t)sizeof(struct ntpdata)) {

11 printf("\npacket too small: %d bytes\n", n);

12 return;

13 }

14 ntp = (struct ntpdata*)buf;

15 version = (ntp->status & VERSION_MASK) >> 3;

16 mode = ntp->status & MODE_MASK;

17 printf("\nv%d, mode %d, strat %d, ", version, mode, ntp->stratum);

18 if (mode == MODE_CLIENT) {

19 printf("client\n");

20 return;

21 }

22 nsec = ntohl(ntp->xmt.int_part) - JAN_1970;

23 useci = ntohl(ntp->xmt.fraction); /* 32-разрядная дробь */

24 usecf = useci; /* дробь в double */

25 usecf /= 4294967296.0; /* деление на 2**32 -> [0, 1.0) */

26 useci = usecf * 1000000.0; /* дробь в миллионную часть */

27 diff.tv_sec = nowptr->tv_sec - nsec;

28 if ((diff.tv_usec = nowptr->tv_usec - useci) < 0) {

29 diff.tv_usec += 1000000;

30 diff.tv_sec--;

31 }

32 useci = (diff.tv_sec * 1000000) + diff.tv_usec; /* diff в мс */

33 printf("clock difference = %d usec\n", useci);

34 }

Ратификация пакета

10-21
Сначала мы проверяем размер пакета, затем выводим его версию, режим и слой (stratum) сервера. Если режимом является
MODE_CLIENT
, пакет является запросом клиента, а не ответом сервера, и мы игнорируем его.

Получение времени передачи из пакета NTP

22-34
В пакете NTP нас интересует поле
xmt
— отметка времени. Это 64-разрядное значение с фиксированной точкой, определяющее момент отправки пакета сервером. Поскольку отметки времени NTP отсчитывают секунды начиная с 1 января 1900 года, а отметки времени Unix — с 1 января 1970 года, сначала мы вычитаем
JAN_1970
(число секунд в 70 годах) из целой части.

Дробная часть — это 32-разрядное целое без знака, которое может принимать значение от 0 до 4 294 967 295 включительно. Оно копируется из 32-разрядного целого (

usecf
) в переменную с плавающей точкой двойной точности (
usecf
) и делится на 4 294 967 296 (2 32). Результат больше либо равен 0.0 и меньше 1.0. Мы умножаем это число на 1 000 000 — число микросекунд в секунде, записывая результат в переменную
useci
как 32-разрядное целое без знака.

Число микросекунд лежит в интервале от 0 до 999 999 (см. упражнение 21.5). Мы преобразуем значение в микросекунды, поскольку отметка времени Unix, возвращаемая функцией

gettimeofday
, возвращается как два целых числа: число секунд и число микросекунд, прошедшее с 1 января 1970 года (UTC). Затем мы вычисляем и выводим разницу между истинным временем узла и истинным временем сервера NTP в микросекундах.

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

Если мы запустим эту программу на узле

macosx
с сервером NTP на узле
freebsd4
, который с помощью многоадресной передачи отправляет пакеты NTP в сеть Ethernet каждые 64 с, то получим следующий результат:

macosx # ssntp 224.0.1.1

joined 224.0.1.1.123 on lo0

joined 224.0.1.1.123 on en1

v4, mode 5, strat 3, clock difference = 661 usec

v4, mode 5, strat 3, clock difference = -1789 usec

  • Читать дальше
  • 1
  • ...
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: