UNIX: разработка сетевых приложений
Часть 241 из 399 Информация о книге
13 err_quit("usage: ssntp <Ipaddress>");14 sockfd = Udp_client(argv[1], "ntp", (void**)&mcastsa, &salen);15 wild = Malloc(salen);16 memcpy(wild, mcastsa. salen); /* копируем семейство и порт */17 sock_set_wild(wild, salen);[3]18 Bind(sockfd, wild, salen); /* связываем сокет с универсальнымадресом */19 #ifdef MCAST20 /* получаем список интерфейсов и обрабатываем каждый интерфейс */21 for (ifi = Get_ifi_info(mcastsa->sa_family, 1); ifi != NULL;22 ifi = ifi->ifi_next) {23 if (ifi->ifi_flags & IFF_MULTICAST) {24 Mcast_join(sockfd, mcastsa, salen, ifi->ififname, 0);25 printf("joined %s on %s\n",26 Sock_ntop(mcastsa, salen), ifi->ifi_name);27 }28 }29 #endif30 from = Malloc(salen);31 for (;;) {32 len = salen;33 n = Recvfrom(sockfd, buf, sizeof(buf), 0, from, &len);34 Gettimeofday(&now, NULL);35 sntp_proc(buf, n, &now);36 }37 }Получение IP-адреса многоадресной передачиПри выполнении программы пользователь должен задать в качестве аргумента командной строки адрес многоадресной передачи, к которому он будет присоединяться. В случае IPv4 это будет 224.0.1.1 или имя12-14. В случае IPv6 это будетntp.mcast.netдля области действия NTP, локальной в пределах сайта. Наша функцияff05::101выделяет в памяти пространство для структуры адреса сокета корректного типа (либо IPv4, либо IPv6) и записывает адрес многоадресной передачи и порт в эту структуру. Если эта программа выполняется на узле, не поддерживающем многоадресную передачу, может быть задан любой IP-адрес, так как в этой структуре задействуются только семейство адресов и порт. Обратите внимание, что наша функцияudp_clientне связывает адрес с сокетом (то есть не вызывает функциюudp_client) — она лишь создает сокет и заполняет структуру адреса сокета.bindСвязывание универсального адреса с сокетомМы выделяем в памяти пространство для другой структуры адреса сокета и заполняем ее, копируя структуру, заполненную функцией15-18. При этом задаются семейство адреса и порт. Мы вызываем нашу функцию sock_set_wild, чтобы присвоить IP-адресу универсальный адрес, а затем вызываем функцию bind.udp_clientПолучение списка интерфейсовНаша функция20-22возвращает информацию обо всех интерфейсах и адресах. Запрашиваемое нами семейство адреса берется из структуры адреса сокета, заполненной функциейget_ifi_infoна основе аргумента командной строки.udp_clientПрисоединение к группеМы вызываем нашу функцию23-27, чтобы присоединиться к группе, заданной аргументом командной строки для каждого интерфейса, поддерживающего многоадресную передачу. Все эти присоединения происходят на одном сокете, который использует эта программа. Как отмечалось ранее, количество присоединений на одном сокете ограничено константойmcast_join(которая обычно имеет значение 20), но лишь немногие многоинтерфейсные узлы используют столько интерфейсов.IP_MAX_MEMBERSHIPSЧтение и обработка всех пакетов NTPВ памяти размещается другая структура адреса сокета для хранения адреса, возвращаемого функцией30-36, и программа входит в бесконечный цикл, считывая все пакеты NTP, которые получает узел, и вызывая нашу функциюrecvfrom(описывается далее) для обработки пакета. Поскольку сокет был связан с универсальным адресом и присоединение к группе произошло на всех интерфейсах, поддерживающих многоадресную передачу, сокет должен получить любой пакет NTP направленной, широковещательной или многоадресной передачи, получаемый узлом. Перед вызовом функцииsntp_procмы вызываем функциюsntp_proc, чтобы получить текущее время, потому что функцияgettimeofdayвычисляет разницу между временем пакета и текущим временем.sntp_procНаша функция
, показанная в листинге 21.13, обрабатывает пакет NTP.sntp_procЛистинг 21.13. Функция sntp_proc: обработка пакета NTР
//ssntp/sntp_proc.c1 #include "sntp.h"2 void3 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);