16.5. Изчакване и повторно предаване
16.5. Изчакване и повторно предаване
Нека да разгледаме времето за изчакване и стратегията за обработка на повторно предаване, използвана от инструментите на Sun RPC. Има две стойности на изчакване:
1. Общото време на изчакване определя колко дълго клиентът чака отговор на сървъра. Тази стойност се използва от TCP и UDP протоколите.
2. Изчакването за повторен опит се използва само от UDP и определя времето за изчакване между повторните опити на клиента, ако не се получи отговор от сървъра.
TCP не трябва да въвежда таймаут за повторен опит, защото е надежден протокол. Ако сървърът не получи заявка от клиента, TCP на клиента ще изтече и клиентът ще препредаде. Когато сървърът получи заявка от клиент, той уведомява последния. Ако известието за получаване се загуби по пътя към клиента, клиентът ще трябва да изпрати отново заявката. Повтарящите се заявки се премахват от сървъра, но известията за тяхното получаване се изпращат на клиента. При надеждните протоколи коректността на доставката (изчакване, повторно предаване, обработка на допълнителни копия на данни и допълнителни известия) се предоставя на транспортния слой и не е част от задачите на RPC библиотеката. Една заявка, изпратена от клиента на RPC слоя, ще бъде получена от сървъра в точно един екземпляр на RPC слоя. В противен случай RPC клиентът ще получи съобщение, че не може да се свърже със сървъра. В същото време няма никакво значение какво се случва на ниво мрежа и транспорт.
След като манипулаторът на клиента е създаден, функцията clnt_control може да се използва за получаване на информация и промяна на свойствата на клиента. Тази функция работи подобно на fcntl за файлови дескриптори или getsockopt и setockopt за сокети:
bool_t clnt_control(КЛИЕНТ *cl, unsigned int заявка, char *ptr);
/*Връща TRUE при успех, FALSE при грешка */
Тук cl е манипулаторът към клиента и към какво сочи ptr зависи от стойността на заявката.
Нека модифицираме клиентската програма в списък 16-2, за да включим това извикване на функция и да покажем стойностите за изчакване. Листинг 16.9 показва текста на новата клиентска програма.
Списък 16.9. Клиентът получава и отпечатва стойности за изчакване на RPC
1 #include "unpipc.h"
2 #include "square.h"
4 main(int argc, char **argv)
8 square_out*outp;
9 struct timeval tv;
11 err_quit("използване: клиент
12 cl = Clnt_create(argv[1], SQUARE_PROG, SQUARE_VERS, argv[3]);
13 Clnt_control(cl, CLGET_TIMEOUT, (char*)&tv);
14 printf("изчакване = %ld сек, %ld usec ", tv.tv_sec, tv.tv_usec);
15 if (clnt_control(cl, CLGET_RETRY_TIMEOUT, (char *) &tv) == TRUE)
16 printf("изчакване за повторен опит = %ld сек, %ld usec ", 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(резултат: %ld ", outp->res1);
Протоколът, който трябва да се използва, е аргумент на командния ред
10-12 Протоколът, който е последният аргумент на clnt_create, сега е посочен като нова опция на командния ред.
Получаване на общата стойност на изчакване
Опитвам се да получа изчакване за повторен опит
15-16 Следната заявка има стойност CLGET_RETRY_TIMEOUT. Това трябва да върне стойност за изчакване за повторен опит, но тази заявка е валидна само за UDP. Следователно, ако функцията върне FALSE, ние не отпечатваме нищо.
Нека също да променим сървърната програма, като добавим към неяизчакване от 1000 секунди вместо 5, за да се гарантира, че е получено време за изчакване по заявка на клиента. Нека стартираме сървъра на bsdi хоста и стартираме клиента два пъти, веднъж с TCP като протокол и веднъж с UDP. Резултатът няма да е това, което очаквахме:
solaris %дата; клиент bsdi 44 tcp; дата
Сряда, 22 април, 14:46:57 MST 1998 г
таймаут = 30 секунди, 0 usec таймаут 30 секунди
bsdi: RPC: Времето изтече
сряда, 22 април, 14:47:22 MST 1998 г., но са изминали само 25 секунди
solaris %дата; клиент bsdi 55 udp; дата
Сряда, 22 април, 14:48:05 MST 1998 г
таймаут = -1 сек, -1 усек някакви глупости
изчакване за повторен опит = 15 сек, 0 usec това изглежда правилно
bsdi: RPC: Времето изтече
Сряда, 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, вместо да променяме съдържанието на клиентския файл.
ЗАБЕЛЕЖКА