Шрифт:
16 static socklen_t clilen; /* максимальная длина sockaddr{} */
17 static void sig_io(int);
18 static void sig_hup(int);
Очередь принимаемых дейтаграмм
3-12
Обработчик сигнала SIGIO
помещает приходящие дейтаграммы в очередь. Эта очередь является массивом структур DG
, который интерпретируется как кольцевой буфер. Каждая структура содержит указатель на принятую дейтаграмму, ее длину и указатель на структуру адреса сокета, содержащую адрес протокола клиента и размер адреса протокола. В памяти размещается столько этих структур, сколько указано в QSIZE
(в данном случае 8), и в листинге 25.2 будет видно, что функция dg_echo
для размещения в памяти всех структур дейтаграмм и адресов сокетов вызывает функцию malloc
. Также происходит выделение памяти под диагностический счетчик cntread
, который будет рассмотрен чуть ниже. На рис. 25.2 приведен массив структур, при этом предполагается, что первый элемент указывает на 150-байтовую дейтаграмму, а длина связанного с ней адреса сокета равна 16. Рис. 25.2. Структуры данных, используемые для хранения прибывающих дейтаграмм и структур адресов их сокетов
Индексы массивов
13-15
Переменная iget
является индексом следующего элемента массива для обработки в основном цикле, а переменная iput
— это индекс следующего элемента массива, в котором сохраняется результат действия обработчика сигнала. Переменная nqueue
обозначает полное количество дейтаграмм, предназначенных для обработки в основном цикле. В листинге 25.2 показан основной цикл сервера — функция
dg_echo
. Листинг 25.2. Функция dg_echo: основной обрабатывающий цикл сервера
//sigio/dgecho01.c
19 void
20 dg_echo(int sockfd_arg, SA *pcliaddr, socklen_t clilen_arg)
21 {
22 int i;
23 const int on = 1;
24 sigset_t zeromask, newmask, oldmask;
25 sockfd = sockfd_arg;
26 clilen = clilen_arg;
27 for (i = 0; i < QSIZE; i++) { /* инициализация очереди */
28 dg[i].dg_data = Malloc(MAXDG);
29 dg[i].dg_sa = Malloc(clilen);
30 dg[i].dg_salen = clilen;
31 }
32 iget = iput = nqueue = 0;
33 Signal(SIGHUP, sig_hup);
34 Signal(SIGIO, sig_io);
35 Fcntl(sockfd, F_SETOWN, getpid);
36 Ioctl(sockfd, FIOASYNC, &on);
37 Ioctl(sockfd. FIONBIO, &on);
38 Sigemptyset(&zeromask); /* инициализация трех наборов сигналов */
39 Sigemptyset(&oldmask);
40 Sigemptyset(&newmask);
41 Sigaddset(&newmask, SIGIO); /* сигнал, который хотим блокировать*/
42 Sigprocmask(SIG_BLOCK, &newmask, &oldmask);
43 for (;;) {
44 while (nqueue == 0)
45 sigsuspend(&zeromask); /* ждем дейтаграмму для обработки */
46 /* разблокирование SIGIO */
47 Sigprocmask(SIG_SETMASK, &oldmask, NULL);
48 Sendto(sockfd, dg[iget].dg_data, dg[iget].dg_len, 0,
49 dg[iget].dg_sa, dg[iget].dg_salen);
50 if (++iget >= QSIZE)
51 iget = 0;
52 /* блокировка SIGIO */
53 Sigprocmask(SIG_BLOCK, &newmask, &oldmask);
54 nqueue--;
55 }
56 }
Инициализация очереди принятых дейтаграмм
27-32
Дескриптор сокета сохраняется в глобальной переменной, поскольку он необходим обработчику сигналов. Происходит инициализация очереди принятых дейтаграмм. Установка обработчиков сигналов и флагов сокетов
33-37
Для сигналов SIGHUP
(он используется для диагностических целей) и SIGIO
устанавливаются обработчики. С помощью функции fcntl
задается владелец сокета, а с помощью функции ioctl
устанавливаются флаги ввода-вывода, управляемого сигналом, и неблокируемого ввода-вывода.