2 void
3 recv_all(int recvfd, socklen_t salen)
4 {
5 int n;
6 char line[MAXLINE + 1];
7 socklen_t len;
8 struct sockaddr *safrom;
9 safrom = Malloc(salen);
10 for (;;) {
11 len = salen;
12 n = Recvfrom(recvfd, line, MAXLINE, 0, safrom, &len);
13 line[n] = 0; /* завершающий нуль */
14 printf("from %s: %s", Sock_ntop(safrom, len), line);
15 }
16 }
Размещение в памяти структуры адреса сокета
9
При каждом вызове функции
recvfrom
в памяти выделяется пространство для структуры адреса сокета, в которую записывается адрес отправителя.
Чтение и вывод дейтаграмм
10-15
Каждая дейтаграмма считывается функцией
recvfrom
, дополняется символом конца строки (то есть нулем) и выводится.
Пример
Мы запускаем программу в двух системах:
freebsd4
и
macosx
. Каждая система видит пакеты, отправляемые другой.
freebsd4 % <b>sendrecv 239.255.1.2 8888</b>
from 172.24.37.78:51297: macosx, 21891
from 172.24.37.78:51297: macosx, 21891
from 172.24.37.78:51297: macosx, 21891
from 172.24.37.78:51297: macosx, 21891
macosx % <b>sendrecv 239.255.1.2 8888</b>
from 172.24.37.94.1215: freebsd4, 55372
from 172.24.37.94.1215: freebsd4, 55372
from 172.24.37.94.1215: freebsd4, 55372
from 172.24.37.94.1215: freebsd4, 55372
21.11. SNTP: простой синхронизирующий сетевой протокол
Синхронизирующий сетевой протокол (Network Time Protocol, NTP) — это сложный протокол синхронизации часов в глобальной или локальной сети. Его точность часто может достигать миллисекунд. В RFC 1305 [76] этот протокол подробно описан, а в RFC 2030 [77] рассматривается протокол SNTP — упрощенная версия NTP, предназначенная для узлов, которым не требуется функциональность полной реализации NTP. Типичной является ситуация, когда несколько узлов в локальной сети синхронизируют свои часы через Интернет с другими узлами NTP, а затем распространяют полученное значение времени в локальной сети с использованием либо широковещательной, либо многоадресной передачи.
В этом разделе мы создадим клиент SNTP, который прослушивает широковещательные или групповые сообщения NTP на всех присоединенных сетях, а затем выводит разницу во времени между пакетом NTP и текущим истинным временем узла. Мы не пытаемся изменить это время, поскольку для этого необходимы права привилегированного пользователя.
Файл
ntp.h
, показанный в листинге 21.11, содержит некоторые из основных определений формата пакета NTP.
Листинг 21.11. Заголовок ntp.h: формат пакета NTP и определения
//ssntp/ntp.h
1 #define JAN_1970 2208988800UL /* 1970 - 1900 в секундах */
2 struct l_fixedpt { /* 64-разрядное число с фиксированной точкой */
3 uint32_t int_part;
4 uint32_t fraction;
5 };
6 struct s_fixedpt { /* 32-разрядное число с фиксированной точкой */
7 u_short int_part;
8 u_short fraction;
9 };
10 struct ntpdata { /* заголовок NTP */
11 u_char status;
12 u_char stratum;
13 u_char ppoll;
14 int precision:8;
15 struct s_fixedpt distance;
16 struct s_fixedpt dispersion;
17 uint32_t refid;
18 struct l_fixedpt reftime;
19 struct l_fixedpt org;
20 struct 1_fixedpt rec;
21 struct l_fixedpt xmt;
22 };
23 #define VERSION_MASK 0x38
24 #define MODE_MASK 0x07
25 #define MODE CLIENT 3
26 #define MODE_SERVER 4
27 #define MODE_BROADCAST 5
2-22 l_fixedpt
задает 64-разрядные числа с фиксированной точкой, используемые NTP для отметок времени, a
s_fixedpt
— 32-разрядные значения с фиксированной точкой, также используемые NTP. Структура
ntpdata
представляет 48-байтовый формат пакета NTP.
В листинге 21.12 пpeдcтaвлeнa функция
main
.
Листинг 21.12. Функция main
//ssntp/main.c
1 #include "sntp.h"
2 int
3 main(int argc, char **argv)
4 {
5 int sockfd;
6 char buf[MAXLINE];
7 ssize_t n;
8 socklen_t salen, len;
9 struct ifi_info *ifi;
10 struct sockaddr *mcastsa, *wild, *from;
11 struct timeval now;
12 if (argc != 2)