- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания UNIX: взаимодействие процессов - Уильям Стивенс
Шрифт:
Интервал:
Закладка:
1. Общий тайм-аут определяет время ожидания ответа сервера клиентом. Это значение используется протоколами TCP и UDP.
2. Тайм-аут повтора используется только UDP и определяет время ожидания между повторами запросов клиента, если ответ от сервера не приходит.
Для протокола TCP необходимость во введении тайм-аута повтора отсутствует, поскольку этот протокол является надежным. Если сервер Не получает запроса от клиента, время ожидания по протоколу TCP со стороны клиента закончится и клиент повторит передачу. Когда сервер получает запрос клиента, он уведомляет об этом последний. Если уведомление о получении будет утрачено по пути к клиенту, тот должен будет еще раз переслать запрос. Повторные запросы сбрасываются сервером, но уведомления об их получении отсылаются клиенту. В надежных протоколах правильность доставки (время ожидания, повторная передача, обработка лишних копий данных и лишних уведомлений) обеспечивается на транспортном уровне и не входит в задачи библиотеки RPC. Один запрос, отправленный клиентом на уровне RPC, будет получен сервером ровно в одном экземпляре на уровне RPC. В противном случае клиент RPC получит сообщение о невозможности связаться с сервером. При этом совершенно не важно, что происходит на сетевом и транспортном уровнях.
После создания дескриптора клиента можно использовать функцию clnt_control для получения информации и изменения свойств клиента. Эта функция работает аналогично fcntl для дескрипторов файлов или getsockopt и setsockopt для сокетов:
#include <rpc/rpc.h>
bool_t clnt_control(CLIENT *cl, unsigned int request, char *ptr);
/* Возвращает TRUE в случае успешного завершения, FALSE – в случае ошибки */
Здесь cl представляет собой дескриптор клиента, а на что указывает ptr — зависит от значения request.
Изменим программу-клиент из листинга 16.2, добавив в нее вызов данной функции, и выведем значения тайм-аутов. В листинге 16.9 приведен текст новой программы-клиента.
Листинг 16.9. Клиент, получающий и печатающий значения времени ожидания RPC//sunrpc/square5/client.c
1 #include "unpipc.h"
2 #include "square.h"
3 int
4 main(int argc, char **argv)
5 {
6 CLIENT *cl;
7 square_in in;
8 square_out *outp;
9 struct timeval tv;
10 if (argc != 4)
11 err_quit("usage: client <hostname> <integer-value> <protocol>");
12 cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, argv[3]);
13 Clnt_control(cl, CLGET_TIMEOUT, (char*)&tv);
14 printf("timeout = %ld sec, %ld usecn", tv.tv_sec, tv.tv_usec);
15 if (clnt_control(cl, CLGET_RETRY_TIMEOUT, (char *) &tv) == TRUE)
16 printf("retry timeout = %ld sec, %ld usecn", tv.tv_sec, tv.tv_usec);
17 in.arg1 = atol(argv[2]);
18 if ((outp = squareproc_1(&in, cl)) == NULL)
19 err_quit("%s", clnt_sperror(cl, argv[1]));
20 printf(result: %ldn", outp->res1);
21 exit(0);
22 }
Используемый протокол является аргументом командной строки10-12 Теперь протокол, являющийся последним аргументом clnt_create, указывается в качестве нового параметра командной строки.
Получение значения общего тайм-аута13-14 Первым аргументом clnt_control является дескриптор клиента, вторым — тип запроса, а третьим — указатель на буфер. Наш первый запрос имеет значение CLGET_TIMEOUT; при этом возвращается значение общего тайм-аута в структуре timeval, адрес которой передается третьим аргументом. Этот запрос корректен для всех протоколов.
Попытка получения тайм-аута повтора15-16 Следующий запрос имеет значение CLGET_RETRY_TIMEOUT. При этом должно возвращаться значение тайм-аута повтора, но этот запрос корректен только для протокола UDP. Следовательно, если функция возвращает значение FALSE, мы ничего не печатаем.
Изменим также и программу-сервер, добавив в нее ожидание продолжительностью 1000 секунд вместо 5, чтобы гарантировать получение тайм-аута по запросу клиента. Запустим сервер на узле bsdi, а клиент запустим дважды, один раз указав в качестве протокола TCP, а другой — UDP. Результат будет не таким, как мы ожидали:
solaris % date ; client bsdi 44 tcp ; date
Wed Apr 22 14:46:57 MST 1998
timeout = 30 sec, 0 usec тайм-аут 30 секунд
bsdi: RPC: Timed out
Wed Apr 22 14:47:22 MST 1998 но прошло только 25 секунд
solaris % date ; client bsdi 55 udp ; date
Wed Apr 22 14:48:05 MST 1998
timeout = –1 sec, –1 usec ерунда какая-то
retry timeout = 15 sec, 0 usec это значение кажется правильным
bsdi: RPC: Timed out
Wed Apr 22 14:48:31 MST 1998 около 25 секунд спустя
В случае с протоколом TCP значение тайм-аута, возвращенное clnt_control, было 30 секунд, но библиотека возвратила ошибку через 25 секунд. Для протокола UDP было получено значение общего тайм-аута –1.
Чтобы понять, что тут происходит, изучим текст заглушки клиента — функции squareproc_1 в файле square_clnt.c, созданном rpcgen. Эта функция вызывает библиотечную функцию с именем clnt_call, причем последним аргументом является структура типа timeval с именем TIMEOUT, объявляемая в этом файле, и инициализируется она значением 25 секунд. Этот аргумент clnt_call отменяет значение общего тайм-аута в 30 секунд для TCP и –1 для UDP. Он используется всегда, если клиент не устанавливает общий тайм-аут явно вызовом clnt_control с запросом CLSET_TIMEOUT. Если мы хотим изменить значение общего тайм-аута, следует вызывать clnt_control, а не изменять содержимое заглушки клиента.
ПРИМЕЧАНИЕ
Единственный способ проверить значение тайм-аута повтора для протокола UDP заключается в просмотре пакетов с помощью tcpdump. При этом можно увидеть, что первая дейтаграмма отправляется сразу после запуска клиента, а следующая — примерно 15 секунд спустя.
Управление соединением по TCP
Если мы будем наблюдать с помощью tcpdump за работой клиента и сервера из предыдущего примера, связывающихся по протоколу TCP, мы увидим, что сначала происходит установка соединения (трехэтапное рукопожатие TCP), затем отправляется запрос клиента и сервер отсылает уведомление о приеме этого запроса. Через 25 секунд после этого клиент отсылает серверу FIN, что вызвано завершением работы клиента, после чего следуют оставшиеся три этапа завершения соединения по TCP. В разделе 2.5 [24] эти этапы описаны подробно.
Мы хотим показать, что Sun RPC использует соединение по TCP следующим образом: новое соединение по TCP устанавливается при вызове clnt_create и оно используется для всех вызовов процедур, связанных с указанной программой и версией. Соединение по TCP завершается явно вызовом clnt_destroy или неявно по завершении процесса клиента:
#include <rpc/rpc.h>
void clnt_destroy(CLIENT *cl);
Начнем с клиента из листинга 16.2 и изменим его, добавив второй вызов процедуры сервера, вызовы clnt_destroy и pause. В листинге 16.10 приведен текст новой программы-клиента.
Листинг 16.10. Клиент для изучения свойств соединения по TCP//sunrpc/square9/client.c
1 #include "unpipc.h" /* наш заголовочный файл*/
2 #include "square.h" /* создается rpcgen */
3 int
4 main(int argc, char **argv)
5 {
6 CLIENT, *cl;
7 square_in in;
8 square_out *outp;
9 if (argc != 3)
10 err_quit("usage: client <hostname> <integer-value>");
11 cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, "tcp");
12 in.arg1 = atol(argv[2]);
13 if ((outp = squareproc_1(&in, cl)) == NULL)
14 err_quit("%s", clnt_sperror(c1, argv[1]));
15 printf("result: %ldn", outp->res1);
16 in.arg1 *= 2;
17 if ((outp = squareproc_1(&in, cl)) == NULL)
18 err_quit("%s", clnt_sperror(cl, argv[1]));
19 printf("result: %ldn", outp->res1);
20 clnt_destroy(cl);
21 pause();
22 exit(0);
23 }
После запуска получим ожидаемый результат:
solaris % client kalae 5
result: 25
result: 100
программа в состоянии ожидания, пока мы не завершим ее вручную
Однако проверить наши предыдущие утверждения можно лишь с помощью результатов работы программы tcpdump. Она показывает, что создается одно соединение по TCP (вызовом clnt_create) и оно используется для обоих запросов клиента. Соединение завершается вызовом clnt_destroy, хотя клиент при этом и не завершает свою работу.
Идентификатор транзакций
Другая часть стратегии тайм-аутов и повторных передач заключается в использовании идентификаторов транзакций (transaction ID или XID) для распознавания запросов клиента и ответов сервера. Когда клиент вызывает функцию RPC, библиотека присваивает этому вызову 32-разрядный целочисленный номер и это значение отсылается в запросе RPC. Сервер должен добавить к своему ответу этот номер. При повторной отсылке запроса идентификатор не меняется. Служит он двум целям: