Читать «UNIX: взаимодействие процессов» онлайн - страница 280

Уильям Ричард Стивенс

1. Клиент проверяет, что XID ответа совпадает с XID запроса. Если совпадения нет, ответ игнорируется. Если используется протокол TCP, у клиента практически нет шансов получить ответ с неправильным идентификатором, но при использовании протокола UDP поверх плохой сети вероятность получения неправильного XID достаточно высока.

2. Серверу разрешается помещать отсылаемые ответы в кэш, и для проверки идентичности ответов используется, в частности, именно XID. Об этом мы вскоре расскажем.

Пакет TI-RPC использует определенный алгоритм вычисления XID для нового запроса. Алгоритм этот описан ниже. Значок ^ означает побитовую операцию XOR (исключающее ИЛИ):

struct timeval now;

gettimeofday(&now, NULL);

xid = getpid() ^ now.tv_sec ^ now.tv_usec;

Кэш повторных ответов

Для включения поддержки кэша повторных ответов в библиотеке RPC сервер должен вызвать функцию svc_dg_enablecache. После включения кэша выключить его нельзя, можно только запустить процесс заново: 

#include <rpc/rpc.h>

int svc_dg_enablecache(SVCXPRT *xprt, unsigned long size);

/* Возвращает 1 в случае успешного завершения. 0 – в случае ошибки */

Здесь xprt представляет собой транспортный дескриптор, являющийся полем структуры svc_req (раздел 16.4). Адрес этой структуры является аргументом процедуры сервера. Размер определяет количество записей в выделяемом кэше.

Итак, эта функция включает поддержку кэширования всех отсылаемых ответов в очереди размером size записей. Каждый ответ однозначно определяется следующими параметрами:

■ номером программы;

■ номером версии;

■ номером процедуры;

■ XID;

■ адресом клиента (IP-адрес + порт UDP).

При получении запроса клиента библиотека RPC ищет в кэше ответ на такой запрос. В случае его наличия ответ отсылается клиенту без повторного вызова процедуры сервера.

Цель использования кэша повторных ответов состоит в том, чтобы не нужно было вызывать процедуру сервера несколько раз при получении нескольких копий запроса клиента. Это может быть нужно в случае, если процедура неидемпотентна. Повторный запрос может быть получен из-за того, что ответ был утерян или у клиента время ожидания меньше, чем время передачи ответа по сети. Обратите внимание, что этот кэш действует только для протоколов, работающих с дейтаграммами (таких, как UDP), поскольку при использовании TCP повторный запрос никогда не может быть получен приложением — он будет обработан TCP (см. упражнение 16.6).

16.6. Семантика вызовов

В листинге 15.24 мы привели пример клиента интерфейса дверей, повторно отсылавшего запрос на сервер при прерывании вызова door_call перехватываемым сигналом. Затем мы показали, что при этом процедура сервера вызывается дважды, а не однократно. Потом мы разделили процедуры сервера на две группы: идемпотентные, которые могут быть вызваны произвольное количество раз без возникновения ошибок, и неидемпотентные, наподобие вычитания определенной суммы из банковского счета.