Литмир - Электронная Библиотека
Содержание  
A
A

Многие реализации имеют объявления, аналогичные приведенному ниже, которое взято из заголовочного файла 4.4BSD

<sys/types.h>
:

/*

  Значение FD_SETSIZE может быть определено пользователем,

  но заданное здесь по умолчанию

  является достаточным в большинстве случаев.

*/

#ifndef FD_SETSIZE

#define FD_SETSIZE 256

#endif

Исходя из этого комментария, можно подумать, что если перед подключением этого заголовочного файла присвоить

FD_SETSIZE
значение, превышающее 256, то увеличится размер наборов дескрипторов, используемых функцией
select
. К сожалению, обычно это не действует.

ПРИМЕЧАНИЕ

Чтобы понять, в чем дело, обратите внимание, что на рис. 16.53 [128] объявляются три набора дескрипторов внутри ядра, а в качестве верхнего предела используется определенное в ядре значение FD_SETSIZE. Единственный способ увеличить размер наборов дескрипторов — это увеличить значение FD_SETSIZE и затем перекомпилировать ядро. Изменения значения без перекомпиляции ядра недостаточно.

Некоторые производители изменяют свои реализации функции

select
, с тем чтобы позволить процессу задавать значение
FD_SETSIZE
, превышающее значение по умолчанию. BSD/OS также изменила реализацию ядра, чтобы допустить большие наборы дескрипторов, кроме того, в ней добавлено четыре новых макроопределения
FD_<i>xxx</i>
для динамического размещения больших наборов дескрипторов в памяти и для работы с ними. Однако с точки зрения переносимости не стоит злоупотреблять использованием больших наборов дескрипторов.

6.4. Функция str_cli (продолжение)

Теперь мы можем переписать нашу функцию

str_cli
, представленную в разделе 5.5 (на этот раз используя функцию
select
), таким образом, чтобы мы получали уведомление, как только завершится процесс сервера. Проблема с предыдущей версией состояла в том, что процесс мог оказаться заблокированным в вызове функции
fgets
, когда что-то происходило на сокете. Наша новая версия этой функции вместо этого блокируется в вызове функции
select
, ожидая готовности для чтения либо стандартного потока ввода, либо сокета. На рис. 6.7 показаны различные условия, обрабатываемые с помощью вызова функции
select
.

UNIX: разработка сетевых приложений - img_51.png

Рис. 6.7. Условия, обрабатываемые функцией select в вызове функции str_cli

Сокет обрабатывает три условия:

1. Если протокол TCP собеседника отправляет данные, сокет становится готовым для чтения, и функция

read
возвращает положительное значение (то есть число байтов данных).

2. Если протокол TCP собеседника отправляет сегмент FIN (процесс завершается), сокет становится готовым для чтения, и функция

read
возвращает нуль (признак конца файла).

3. Если TCP собеседника отправляет RST (узел вышел из строя и перезагрузился), сокет становится готовым для чтения, и функция

read
возвращает -1, а переменная
errno
содержит код соответствующей ошибки.

В листинге 6.1[1] представлен исходный код этой версии функции.

Листинг 6.1. Реализация функции str_cli с использованием функции select (усовершенствованный вариант находится в листинге 6.2)

//select/strcliselect01.c

 1 #include &quot;unp.h&quot;

 2 void

 3 str_cli(FILE *fp, int sockfd)

 4 {

 5  int maxfdp1;

 6  fd_set rset;

 7  char sendline[MAXLINE], recvline[MAXLINE];

 8  FD_ZERO(&amp;rset);

 9  for (;;) {

10   FD_SET(fileno(fp), &amp;rset);

11   FD_SET(sockfd, &amp;rset);

12   maxfdp1 = max(fileno(fp), sockfd) + 1;

13   Select(maxfdp1, &amp;rset, NULL, NULL, NULL);

14   if (FD_ISSET(sockfd, &amp;rset)) { /* сокет готов для чтения */

15    if (Readline(sockfd, recvline, MAXLINE) == 0)

16     err_quit(&quot;str_cli: server terminated prematurely&quot;);

17    Fputs(recvline, stdout);

18   }

19   if (FD_ISSET(fileno(fp), &amp;rset)) { /* входное устройство готово для

                                           чтения */

20    if (Fgets(sendline, MAXLINE, fp) == NULL)

21     return; /* все сделано */

22    Writen(sockfd, sendline, strlen(sendline));

23   }

24  }

25 }

Вызов функции select

8-13
 Нам нужен только один набор дескрипторов — для проверки готовности сокета для чтения. Этот набор дескрипторов инициализируется макросом
FD_ZERO
, после чего с помощью макроса
FD_SET
устанавливаются два бита: бит, соответствующий указателю файла
fp
стандартного потока ввода-вывода, и бит, соответствующий дескриптору сокета
sockfd
. Функция
fileno
преобразует указатель файла стандартного потока ввода-вывода в соответствующий ему дескриптор. Функция
select
(а также
poll
) работает только с дескрипторами.

Функция

select
вызывается после определения максимального из двух дескрипторов. В этом вызове указатель на набор дескрипторов для записи и указатель на набор дескрипторов с исключениями являются пустыми. Последний аргумент (ограничение по времени) также является пустым указателем, поскольку мы хотим, чтобы процесс был блокирован, пока не будут готовы данные для чтения.

Обработка сокета, готового для чтения
вернуться

1

Все исходные коды программ, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com.

66
{"b":"225366","o":1}