Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 [ 140 ] 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

и клиент повторит передачу. Когда сервер ползд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])): продолжение



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 [ 140 ] 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.