Главная страница Взаимодействие нетривиальных процессов и клиент повторит передачу. Когда сервер ползд1ает запрос клиента, он уведомляет об этом последний. Если уведомление о ползд1ении будет утрачено по пути к клиенту, тот должен будет еще раз переслать запрос. Повторные запросы сбрасываются сервером, но уведомления об их получении отсылаются клиенту. В надежных протоколах правильность доставки (время ожидания, повторная передача, обработка лищних копий данных и лищних уведомлений) обеспечивается на транспортном уровне и не входит в задачи библиотеки RPC. Один запрос, отправленный клиентом на уровне RFC, будет ползд1ен сервером ровно в одном экземпляре на уровне RPC. В противном слзд1ае клиент RPC ползд1ит сообщение о невозможности связаться с сервером. При этом соверщенно не важно, что происходит на сетевом и транспортном уровнях. После создания дескриптора клиента можно использовать функцию с1 nt control для ползд1ения информации и изменения свойств клиента. Эта функция работает аналогично fcntl для дескрипторов файлов или getsockopt и setsockopt для сокетов: #include <rpc/rpc.h> bool t clnt control(CLIENT *cl. unsigned 1nt request, char *ptr): /* Возвращает TRUE в случае успешного завершения. FALSE - в случае ошибки */ Здесь с/ представляет собой дескриптор клиента, а на что указывает ptr - зависит от значения request. Изменим программу-клиент из листинга 16.2, добавив в нее вызов данной функции, и выведем значения тайм-аутов. В листинге 16.9 приведен текст новой программы-клиента. Листинг 16.9. Клиент, получающий и печатающий значения времени ожидания RPC sunrpc/squareS/client.c 1 #include unpipc.h 2 #include square.h 3 int 4 maindnt argc. char **argv) 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[l]. SQUARE PROG. SQUAREJERS. argv[3]): 13 Clnt control(cl. CLGETJIMEOUT. (char*) &tv): 14 printf( timeout = *ld sec. *ld usec\n . tv.tv sec. tv.tv usec): 15 if (clnt control(cl. CLGET RETRY TIMEOUT. (char *) &tv) == TRUE) 16 printf( retry timeout = *ld sec. *ld usec\n . tv.tv sec. tv.tv usec): 17 in.argl = atol(argv[2]): 18 if ( (outp = squareproc l(&in. cD) == NULL) 19 err quit( *s . clnt sperror(cl. argv[l])): 20 printf( result: ХШп . outp->resl): , л продолжение -a Листинг 16.9 (продолжение) 21 ex1t(0): 22 } Используемый протокол является аргументом командной строки 10-12 Теперь протокол, являющийся последним аргументом clnt create, указывается в качестве нового параметра командной строки. Получение значения общего тайм-аута 13-14 Первым аргументом с1 nt control является дескриптор клиента, вторым - тип запроса, а третьим - указатель на буфер. Нащ первый запрос имеет значение CLGET TIMEOUT; при этом возвращается значение общего тайм-аута в структуре timeval, адрес которой передается третьим аргументом. Этот запрос корректен для всех протоколов. Попытка получения тайм-аута повтора 15-16 Следующий запрос имеет значение CLGET RETRY TIMEOUT. При этом должно возвращаться значение тайм-аута повтора, но этот запрос корректен только для протокола UDP. Следовательно, если функция возвращает значение FALSE, мы ничего не печатаем. Изменим также и программу-сервер, добавив в нее ожидание продолжительностью 1000 секунд вместо 5, чтобы гарантировать получение тайм-аута по запросу клиента. Запустим сервер на узле bsdi, а клиент запустим дважды, один раз указав в качестве протокола TCP, а другой - UDP. Результат будет не таким, как мы ожидали: Solaris X date ; client bsdi 44 tcp ; date Wed Apr 22 14:46:57 MSI 1998 timeout = 30 sec. 0 usee тайм-аут 30 секунд bsdi: RPC: Timed out Wed Apr 22 14:47:22 MST 1998 но прошло только 25 секунд Solaris X date ; client bsdi 55 udp ; date Wed Apr 22 14:48:05 MST 1998 timeout = -1 sec. -1 usee ерунда какая-то retry timeout = 15 sec. 0 usee это значение кажется правильным bsdi: RPC: Timed out Wed Apr 22 14:48:31 MST 1998 около 25 секунд спустя В слзд1ае с протоколом TCP значение тайм-аута, возвращенное clnt control, было 30 секунд, но библиотека возвратила ошибку через 25 секунд. Для протокола UDP было получено значение общего тайм-аута -1. Чтобы понять, что тут происходит, ИЗЗД1ИМ текст заглушки клиента - функции squareproc l в файле square clnt.c, созданном rpcgen. Эта функция вызывает библиотечную функцию с именем clnt call, причем последним аргументом является структура типа timeval с именем TIMEOUT, объявляемая в этом файле, и инициализируется она значением 25 секунд. Этот аргумент с1 nt cal 1 отменяет значение общего тайм-аута в 30 секунд для TCP и -1 для UDP. Он используется всегда, если клиент не устанавливает общий тайм-аут явно вызовом с1 nt control с запросом CLSET TIMEOUT. Если мы хотим изменить значение общего тайм-аута, следует вызывать с1 nt control, а не изменять содержимое заглушки клиента. ПРИМЕЧАНИЕ - Единственный способ проверить значение тайм-аута повтора для протокола UDP заключается в просмотре пакетов с помощью tcpdump. При этом можно увидеть, что первая дейтафамма отправляется сразу после запуска клиента, а следующая - примерно 15 секунд спустя. Управление соединением по TCP Если мы будем наблюдать с помощью tcpdump за работой клиента и сервера из предыдущего примера, связывающихся по протоколу TCP, мы увидим, что сначала происходит установка соединения (трехэтапное рукопожатие TCP), затем отправляется запрос клиента и сервер отсылает уведомление о приеме этого запроса. Через 25 секунд после этого клиент отсылает серверу FIN, что вызвано за-верщением работы клиента, после чего следуют оставшиеся три этапа заверщения соединения по TCP. В разделе 2.5 [24] эти этапы описаны подробно. Мы хотим показать, что Sun RPC использует соединение по TCP следующим образом: новое соединение по TCP устанавливается при вызове с1 ntcreate и оно используется для всех вызовов процедур, связанных с указанной программой и версией. Соединение по TCP завершается явно вызовом с1 ntdestroy или неявно по завершении процесса клиента: #include <rpc/rpc.h> void clnt destroy(CLIENT *c/): Начнем с клиента из листинга 16.2 и изменим его, добавив второй вызов процедуры сервера, вызовы с1 nt 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) 6 CLIENT. *cl: 7 squarejn in; 8 square out *outp: 9 if (argc != 3) 10 err quit( usage: client <hostname> <integer-value> ): 11 cl = Clnt create(argv[l]. SQUARE PROG. SQUAREJERS. tcp ): 12 in.argl = atoi(argv[2]): 13 if ( (outp = squareprocJ(&in. cD) == NULL) 14 err quit( *s . clnt sperror(cl, argv[l])): 15 printf( result: *ld\n . outp->resl): 16 in.argl *= 2; 17 if ( (outp = squareproc K&in. cD) == NULL) 18 err quit( s . clnt sperror(cl. argvEl])): продолжение
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |