Читаем UNIX: разработка сетевых приложений полностью

18  sig_alrm(SIGALRM); /* отправка первого пакета */

19  iov.iov_base = recvbuf;

20  iov.iov_len = sizeof(recvbuf);

21  msg.msg_name = pr-sarecv;

22  msg.msg_iov = iov;

23  msg.msg_iovlen = 1;

24  msg.msg_control = controlbuf;

25  for (;;) {

26   msg.msg_namelen = pr-salen;

27   msg.msg_controllen = sizeof(controlbuf);

28   n = recvmsg(sockfd, msg, 0);

29   if (n 0) {

30    if (errno == EINTR)

31     continue;

32    else

33     err_sys("recvmsg error");

24   }

35   Gettimeofday(tval, NULL);

36   (*pr-fproc)(recvbuf, n, msg, tval);

37  }

38 }

Создание сокета

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

Выполнение инициализации для протокола

14-15 Мы выполняем функцию инициализации для выбранного протокола. Для IPv6 такая функция представлена в листинге 28.7.

Установка размера приемного буфера сокета

16-17 Пытаемся установить размер приемного буфера сокета, равный 61 440 байт (60x1024) — этот размер больше задаваемого по умолчанию. Это делается в расчете на случай, когда пользователь проверяет качество связи с помощью программы ping, обращаясь либо к широковещательному адресу IPv4, либо к групповому адресу. В обоих случаях может быть получено большое количество ответов. Увеличивая размер буфера, мы уменьшаем вероятность того, что приемный буфер переполнится.

Отправка первого пакета

18 Запускаем обработчик сигнала, который, как мы увидим, посылает пакет и создает сигнал SIGALRMодин раз в секунду. Обычно обработчик сигналов не запускается напрямую, как у нас, но это можно делать. Обработчик сигналов является обычной функцией языка С, просто в нормальных условиях он асинхронно запускается ядром.

Подготовка msghdr для recvmsg

19-24 Мы записываем значения в неизменяемые поля структур msghdrи iovec, которые будут передаваться функции recvmsg.

Бесконечный цикл для считывания всех ICMP-сообщений

25-37 Основной цикл программы является бесконечным циклом, считывающим все пакеты, возвращаемые на символьный сокет ICMP. Вызывается функция gettimeofdayдля регистрации времени получения пакета, а затем вызывается соответствующая функция протокола ( proc_v4или proc_v6) для обработки ICMP-сообщения.

В листинге 28.5 приведена функция tv_sub, вычисляющая разность двух структур timevalи сохраняющая результат в первой из них.

Листинг 28.5. Функция tv_sub: вычитание двух структур timeval

//lib.tv_sub.c

 1 #include "unp.h"

 2 void

 3 tv_sub(struct timeval *out, struct timeval *in)

 4 {

 5  if ((out-tv_usec -= in-tv_usec) 0) { /* out -= in */

 6   --out-tv_sec;

 7   out-tv_usec += 1000000;

 8  }

 9  out-tv_sec -= in-tv_sec;

10 }

В листинге 28.6 приведена функция proc_v4, обрабатывающая все принимаемые сообщения ICMPv4. Можно также обратиться к рис. А.1, на котором изображен формат заголовка IPv4. Кроме того, следует осознавать, что к тому моменту, когда процесс получает на символьном сокете ICMP-сообщение, ядро уже проверило, что основные поля в заголовке IPv4 и в сообщении ICMPv4 действительны [128, с. 214, с. 311].

Листинг 28.6.Функция proc_v4: обработка сообщений ICMPv4

//ping/prov_v4.c

 1 #include "ping.h"

 2 void

 3 proc_v4(char *ptr, ssize_t len, struct msghdr *msg, struct timeval *tvrecv)

 4 {

 5  int hlen1, icmplen;

 6  double rtt;

 7  struct ip *ip;

 8  struct icmp *icmp;

 9  struct timeval *tvsend;

10  ip = (struct ip*)ptr; /* начало IP-заголовка */

11  hlen1 = ip-ip_hl 2; /* длина IP-заголовка */

Перейти на страницу:

Похожие книги

Основы программирования в Linux
Основы программирования в Linux

В четвертом издании популярного руководства даны основы программирования в операционной системе Linux. Рассмотрены: использование библиотек C/C++ и стан­дартных средств разработки, организация системных вызовов, файловый ввод/вывод, взаимодействие процессов, программирование средствами командной оболочки, создание графических пользовательских интерфейсов с помощью инструментальных средств GTK+ или Qt, применение сокетов и др. Описана компиляция программ, их компоновка c библиотеками и работа с терминальным вводом/выводом. Даны приемы написания приложений в средах GNOME® и KDE®, хранения данных с использованием СУБД MySQL® и отладки программ. Книга хорошо структурирована, что делает обучение легким и быстрым. Для начинающих Linux-программистов

Нейл Мэтью , Ричард Стоунс , Татьяна Коротяева

ОС и Сети / Программирование / Книги по IT
1001 совет по обустройству компьютера
1001 совет по обустройству компьютера

В книге собраны и обобщены советы по решению различных проблем, которые рано или поздно возникают при эксплуатации как экономичных нетбуков, так и современных настольных моделей. Все приведенные рецепты опробованы на практике и разбиты по темам: аппаратные средства персональных компьютеров, компьютерные сети и подключение к Интернету, установка, настройка и ремонт ОС Windows, работа в Интернете, защита от вирусов. Рассмотрены не только готовые решения внезапно возникающих проблем, но и ответы на многие вопросы, которые возникают еще до покупки компьютера. Приведен необходимый минимум технических сведений, позволяющий принять осознанное решение.Компакт-диск прилагается только к печатному изданию книги.

Юрий Всеволодович Ревич

Программирование, программы, базы данных / Интернет / Компьютерное «железо» / ОС и Сети / Программное обеспечение / Книги по IT