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 IPV6
39 if (FD_ISSET(fd6, &rset))
40 if (readable_v6() <= 0)
41 continue;
42 #endif
43 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 }
32-34
Прослушиваемый доменный сокет Unix проверяется в первую очередь, и если он готов, запускается функция readable_listen
. Переменная nready
— количество дескрипторов, которое функция select возвращает как готовые к чтению — является глобальной. Каждая из наших функций readablе_XXX
уменьшает ее значение на 1, и новое значение этой переменной является возвращаемым значением функции. Когда ее значение достигает нуля, это говорит о том, что все готовые к чтению дескрипторы обработаны, и поэтому функция select
вызывается снова.
35-42
Проверяется символьный сокет ICMPv4, а затем символьный сокет ICMPv6.
43-49
Затем проверяется, готов ли для чтения какой-нибудь из присоединенных доменных сокетов Unix. Готовность для чтения какого-либо из таких сокетов обозначает, что клиент отослал дескриптор или завершился.
В листинге 28.26 приведена функция readable_listen
, вызываемая, когда прослушиваемый сокет готов для чтения. Это указывает на новое клиентское соединение.
Листинг 28.26. Обработка нового соединения клиента
//icmpd/readablе_listen.c
1 #include "icmpd.h"
2 int
3 readable_listen(void)
4 {
5 int i, connfd;
6 socklen_t clilen;
7 clilen = sizeof(cliaddr);
8 connfd = Accept(listenfd, (SA*)&cliaddr, &clilen);
9 /* поиск первой свободной структуры в массиве client[] */
10 for (i = 0; i < FD_SETSIZE; i++)
11 if (client[i].connfd < 0) {
12 client[i].connfd = connfd; /* сохранение дескриптора */
13 break;
14 }
15 if (i == FD_SETSIZE) {
16 close(connfd); /* невозможно обработать новый клиент */
17 return(--nready); /* грубое закрытие нового соединения */
18 }
19 printf("new connection, i = %d, connfd = %d\n", i, connfd);
20 FD_SET(connfd, &allset); /* добавление нового дескриптора в набор */
21 if (connfd > maxfd)
22 maxfd = connfd; /* для select() */
23 if (i > maxi)
24 maxi = i; /* максимальный индекс в массиве client[] */
25 return(--nready);
26 }
7-25
Принимается соединение и используется первый свободный элемент массива client
. Код данной функции скопирован из начала кода, приведенного в листинге 6.4. Если свободных элементов в массиве нет, мы закрываем новое соединение и занимаемся обслуживанием уже имеющихся клиентов.
Когда присоединенный сокет готов для чтения, вызывается функция readablе_conn
(листинг 28.27), а ее аргументом является индекс данного клиента в массиве client.
Листинг 28.27. Считывание данных и, возможно, дескриптора от клиента
//icmpd/readable_conn.c
1 #include "icmpd.h"
2 int
3 readable_conn(int I)
4 {
5 int unixfd, recvfd;
6 char c;
7 ssize_t n;
8 socklen_t len;
9 struct sockaddr_storage ss;
10 unixfd = client[i].connfd;
11 recvfd = -1;