UNIX: разработка сетевых приложений
Часть 325 из 399 Информация о книге
11 struct sockaddr_un cliaddr;12 /* прототипы функций */13 int readable_conn(int);14 int readable_listen(void);15 int readable_v4(void);16 int readable_v6(void);Массив clientПоскольку демон может обрабатывать любое количество клиентов, для сохранения информации о каждом клиенте используется массив структур2-17. Они аналогичны структурам данных, которые использовались в разделе 6.8. Кроме дескриптора для доменного сокета Unix, через который осуществляется связь с клиентом, сохраняется также семейство адресов клиентского UDP-сокетаclientилиAF_INETи номер порта, связанного с сокетом. Далее объявляются прототипы функций и глобальные переменные, совместно используемые этими функциями.AF_INET6В листинге 28.24 приведена первая часть функции main.
Листинг 28.24. Первая часть функции main: создание сокетов
//icmpd/icmpd.c1 #include "icmpd.h"2 int3 main(int argc, char **argv)4 {5 int i, sockfd;6 struct sockaddr_un sun;7 if (argc != 1)8 err_quit("usage: icmpd");9 maxi = -1; /* индекс массива client[] */10 for (i = 0; i < FD_SETSIZE; i++)11 client[i].connfd = -1; /* -1 означает свободный элемент */12 FD_ZERO(&allset);13 fd4 = Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);14 FD_SET(fd4, &allset);15 maxfd = fd4;16 #ifdef IPV617 fd6 = Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);18 FD_SET(fd6, &allset);19 maxfd = max(maxfd, fd6);20 #endif21 listenfd = Socket(AF_UNIX, SOCK_STREAM, 0);22 sun.sun_family = AF_LOCAL;23 strcpy(sun.sun_path, ICMPD_PATH);24 unlink(ICMPD_PATH);25 Bind(listenfd, (SA*)&sun, sizeof(sun));26 Listen(listenfd, LISTENQ);27 FD_SET(listenfd, &allset);28 maxfd = max(maxfd, listenfd);Инициализация массива clientИнициализируется массив9-10путем присваивания значения -1 элементу присоединенного сокета.clientСоздание сокетовСоздаются три сокета: символьный сокет ICMPv4, символьный сокет ICMPv6 и потоковый доменный сокет Unix. Мы связываем при помощи функции12-28свое заранее известное полное имя с сокетом и вызываем функциюbind. Это сокет, к которому клиенты присоединяются с помощью функцииlisten. Для функцииconnectтакже вычисляется максимальный дескриптор, а для вызовов функцииselectв памяти размещается структура адреса сокета.acceptВ листинге 28.25 приведена вторая часть функции
. Она содержит бесконечный цикл, вызывающий функциюmainв ожидании, когда будет готов к чтению какой-либо из дескрипторов демона.selectЛистинг 28.25. Вторая часть функции main: обработка готового к чтению дескриптора
//icmpd/icmpd.c29 for (;;) {30 rset = allset;31 nready = Select(maxfd+1, &rset, NULL, NULL, NULL);32 if (FD_ISSET(listenfd, &rset))33 if (readable_listen() <= 0)34 continue;35 if (FD_ISSET(fd4, &rset))36 if (readable_v4() <= 0)37 continue;38 #ifdef IPV639 if (FD_ISSET(fd6, &rset))40 if (readable_v6() <= 0)41 continue;42 #endif43 for (i = 0; i <= maxi; i++) { /* проверка всех клиентов */44 if ( (sockfd = client[i].connfd) < 0)45 continue;46 if (FD_ISSET(sockfd, &rset))47 if (readable_conn(i) <= 0)48 break; /* готовых дескрипторов больше нет */49 }50 }51 exit(0);52 }Проверка прослушиваемого доменного сокета UnixПрослушиваемый доменный сокет Unix проверяется в первую очередь, и если он готов, запускается функция32-34. Переменнаяreadable_listen— количество дескрипторов, которое функция select возвращает как готовые к чтению — является глобальной. Каждая из наших функцийnreadyуменьшает ее значение на 1, и новое значение этой переменной является возвращаемым значением функции. Когда ее значение достигает нуля, это говорит о том, что все готовые к чтению дескрипторы обработаны, и поэтому функцияreadablе_XXXвызывается снова.select