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
В случае с протоколом 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
Начнем с клиента из листинга 16.2 и изменим его, добавив второй вызов процедуры сервера, вызовы clnt_destroy и pause. В листинге 16.10 приведен текст новой программы-клиента.
//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: %ld\n", 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: %ld\n", outp-res1);
20 clnt_destroy(cl);
21 pause;
22 exit(0);
23 }
После запуска получим ожидаемый результат:
solaris % client kalae 5
result: 25
result: 100