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

82 Прежде чем обработчик сигналов возвращает управление, он увеличивает счетчик на единицу в соответствии с количеством дейтаграмм, прочитанных за один сигнал. Этот массив распечатывается программой в листинге 25.4 и представляет собой диагностическую информацию для обработки сигнала SIGHUP.

Последняя функция (листинг 25.4) представляет собой обработчик сигнала SIGHUP, который выводит массив cntread. Он считает количество дейтаграмм, прочитанных за один сигнал.

Листинг 25.4. Обработчик сигнала SIGHUP

//sigio/dgecho01.c

84 static void

85 sig_hup(int signo)

86 {

87  int i;

88  for (i = 0; i <= QSIZE; i++)

89   printf("cntread[%d] = %ld\n", i, cntread[i]);

90 }

Чтобы проиллюстрировать, что сигналы не буферизуются и что в дополнение к установке флага, указывающего на управляемый сигналом ввод-вывод, необходимо перевести сокет в неблокируемый режим, запустим этот сервер с шестью клиентами одновременно. Каждый клиент посылает серверу 3645 строк (для отражения). При этом каждый клиент запускается из сценария интерпретатора в фоновом режиме, так что все клиенты стартуют приблизительно одновременно. Когда все клиенты завершены, серверу посылается сигнал SIGHUP, в результате чего сервер выводит получившийся массив cntread:

linux % udpserv01

cntread[0] = 2

cntread[1] = 21838

cntread[2] = 12

cntread[3] = 1

cntread[4] = 0

cntread[5] = 1

cntread[6] = 0

cntread[7] = 0

cntread[8] = 0

Большую часть времени обработчик сигналов читает только одну дейтаграмму, но бывает, что готово больше одной дейтаграммы. Ненулевое значение счетчика cntread[0] получается потому, что сигнал генерируется в процессе выполнения клиента. Мы считываем дейтаграммы в цикле обработчика сигнала. Дейтаграмма, прибывшая во время считывания других дейтаграмм, будет считана вместе с этими дейтаграммами (в том же вызове обработчика), а сигнал об ее прибытии будет отложен и доставлен процессу после завершения обработчика. Это приведет к повторному вызову обработчика, но считывать ему будет нечего (отсюда cntread[0]>0). Наконец, можно проверить, что взвешенная сумма элементов массива (21 838×1 + 12×2 + 1×3+1×5=21 870) равна 6×3645 (количество клиентов × количество строк клиента).

<p>25.4. Резюме</p>

При управляемом сигналом вводе-выводе ядро уведомляет процесс сигналом SIGIO, если «что-нибудь» происходит на сокете.

■ Для присоединенного TCP-сокета существует множество ситуаций, которые вызывают такое уведомление, что делает эту возможность практически бесполезной.

■ Для прослушиваемого TCP-сокета уведомление приходит процессу только в случае готовности принятия нового соединения.

■ Для UDP такое уведомление означает, что либо пришла дейтаграмма, либо произошла асинхронная ошибка: в обоих случаях вызывается recvfrom.

С помощью метода, аналогичного применяемому для сервера NTP, был изменен эхо-сервер UDP для работы с вводом-выводом, управляемым сигналом: мы стремимся выполнить чтение дейтаграммы как можно быстрее после ее прибытия, чтобы получить точную отметку времени прибытия и поставить дейтаграмму в очередь для дальнейшей обработки.

<p>Упражнения</p>

1. Далее приведен альтернативный вариант цикла, рассмотренного в листинге 25.2:

for (;;) {

 Sigprocmask(SIG_BLOCK, &newmask, &oldmask);

 while (nqueue == 0)

  sigsuspend(&zeromask); /* ожидание дейтаграммы для обработки */

 nqueue--;

 /* разблокирование SIGIO */

 Sigprocmask(SIG_SETMASK, &oldmask, NULL);

 Sendto(sockfd, dg[iget].dg_data, dg[iget].dg_len, 0,

  dg[iget].dg_sa, dg[iget].dg_salen);

 if (++iget >= QSIZE)

  iget = 0;

}

Верна ли такая модификация?

<p>Глава 26</p><p>Программные потоки</p><p>26.1. Введение</p>

Согласно традиционной модели Unix, когда процессу требуется, чтобы некое действие было выполнено каким-либо другим объектом, он порождает дочерний процесс, используя функцию fork, и этим порожденным процессом выполняется необходимое действие. Большинство сетевых серверов под Unix устроены именно таким образом, как мы видели при рассмотрении примера параллельного (concurrent) сервера: родительский процесс осуществляет соединение с помощью функции accept и порождает дочерний процесс, используя функцию fork, а затем дочерний процесс занимается обработкой клиентского запроса.

Хотя эта концепция с успехом использовалась на протяжении многих лет, с функцией fork связаны определенные неудобства.

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

Все книги серии Мастер-класс

Секреты резьбы по дереву
Секреты резьбы по дереву

Изделия из древесины и материалов, имитирующих ее текстуру, привычным образом окружают нас в повседневной жизни, поэтому мы относимся к ней как к чему-то обыденному. Но как только ее коснется умелая рука мастера резьбы по дереву, рождается произведение искусства и раскрываются такие качества древесины, как богатая фактура, разнообразие цветов, особая теплота. Эта книга поможет читателю открыть для себя удивительный мир творчества и познать секреты резьбы по дереву. Автор надеется, что начинающие резчики найдут в ней интересный и полезный материал, который позволит им стать мастерами. В приложении представлены рисунки орнаментов и различных узоров, которые на первых порах можно копировать, а по мере приобретения навыка на их основе разрабатывать свои образцы.

Галина Алексеевна Серикова

Сделай сам / Хобби и ремесла / Руководства / Дом и досуг / Словари и Энциклопедии

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