Книга: UNIX: разработка сетевых приложений
6.4. Функция str_cli (продолжение)
Разделы на этой странице:
6.4. Функция str_cli (продолжение)
Теперь мы можем переписать нашу функцию str_cli
, представленную в разделе 5.5 (на этот раз используя функцию select
), таким образом, чтобы мы получали уведомление, как только завершится процесс сервера. Проблема с предыдущей версией состояла в том, что процесс мог оказаться заблокированным в вызове функции fgets
, когда что-то происходило на сокете. Наша новая версия этой функции вместо этого блокируется в вызове функции select
, ожидая готовности для чтения либо стандартного потока ввода, либо сокета. На рис. 6.7 показаны различные условия, обрабатываемые с помощью вызова функции select
.
Рис. 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 "unp.h"
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(&rset);
9 for (;;) {
10 FD_SET(fileno(fp), &rset);
11 FD_SET(sockfd, &rset);
12 maxfdp1 = max(fileno(fp), sockfd) + 1;
13 Select(maxfdp1, &rset, NULL, NULL, NULL);
14 if (FD_ISSET(sockfd, &rset)) { /* сокет готов для чтения */
15 if (Readline(sockfd, recvline, MAXLINE) == 0)
16 err_quit("str_cli: server terminated prematurely");
17 Fputs(recvline, stdout);
18 }
19 if (FD_ISSET(fileno(fp), &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
вызывается после определения максимального из двух дескрипторов. В этом вызове указатель на набор дескрипторов для записи и указатель на набор дескрипторов с исключениями являются пустыми. Последний аргумент (ограничение по времени) также является пустым указателем, поскольку мы хотим, чтобы процесс был блокирован, пока не будут готовы данные для чтения.
Обработка сокета, готового для чтения
14-18
Если по завершении функции select
сокет готов для чтения, отраженная строка считывается функцией readline
и выводится функцией fputs
.
Обработка ввода, допускающего возможность чтения
19-23
Если стандартный поток ввода готов для чтения, строка считывается функцией fgets
и записывается в сокет с помощью функции writen
.
Обратите внимание, что используются те же четыре функции ввода-вывода, что и в листинге 5.4: fgets
, writen
, readline
и fputs
, но порядок их следования внутри функции str_cli
изменился. Раньше выполнение функции str_cli
определялось функцией fgets
, а теперь ее место заняла select
. С помощью всего нескольких дополнительных строк кода (сравните листинги 6.1 и 5.4) мы значительно увеличили устойчивость клиента.
- 16.2. Неблокируемые чтение и запись: функция str_cli (продолжение)
- * Продолжение следует??
- ББД продолжение
- Продолжение беседы
- 6.6. Функция shutdown
- 2.1.3. Функция getopt_long()
- Класс StreamReader
- Группировка по встроенным функциям и UDF
- Продолжение линии 1.0
- SERVER CLIENT MAPPING
- 19.1.1. Функция jQuery()
- Using Double Quotes to Resolve Variables in Strings with Embedded Spaces