Plik hello. h utworzony przez rpcgen będzie włączany do kodu procedur wejścia serwera i klienta. Przed wielokrotnym włączeniem pliku chronią dyrektywy preprocesora #i f ndef _HEL-LO_H_RPCGEN, #define _HELLO_H_RPCGEN oraz #endif. Włączenie pliku <rpc/rpcii> umieszczone w pliku hello. h,jak odnotowano w wewnętrznym komentarzu z pliku rpc. h, powoduje: „...tylko włączenie miliardów plików nagłówkowych koniecznych do realizowania zdalnych
wywołań procedur"1. Zmienna cplusplus została użyta w celu stwierdzenia, czy obecne jest
środowisko C++. W środowisku tym kompilator dodaje wewnętrznie szereg przedrostków do nazw funkcji kodujących typy parametrów funkcji. Te przeredagowane nazwy umożliwiają sprawdzenie, czy parametry funkcji podczas wywołań są zgodne z ich definicjami. Kompilator C nie zapewnia przeredagowanych nazw funkcji, potrzebnych kompilatorowi C++. W związku z tym kompilator C++ należy przestrzec przed tym, że będą stosowane nie przeredagowane
nazwy funkcji. Do tego celu służy dyrektywa #ifdef _cplusplus.
Plik nagłówkowy zawiera także (w postaci stałych typu unsigned long) identyfikatory poprzedzone słowami kluczowymi program i yersion w pliku definicji protokołu. Ponieważ w wywołaniu programu rpcgen zastosowaliśmy opcję -c (nakazującą generowanie kodu zgodnego z normą ANSI C), interesująca nas instrukcja zawiera odgałęzienie if
dyrektywy preprocesora (#if defined (_STDC_)). Jeżeli nazwa zdalnej procedury
w pliku definiującym protokół została podana dużymi literami, w pliku nagłówkowym będzie już zapisana małymi. Nazwa procedury jest zdefiniowana jako numer procedury z pliku definicyjnego rzutowany na liczbę długą bez znaku (na typ unsigned long). Stałą tę napotkamy jeszcze raz w serwerowej procedurze wejścia, w instrukcji switch wybierającej właściwy kod wywołujący zdalną procedurę. Dalej znajdują się dwa prototypy funkq'i print_helło. Pierwszy z nich, określający funkcję print_hello_l, jest używany w procedurze wejścia klienta, drugi, print_hello_l_svc— w procedurze wejścia serwera. Konwencja nadawania nazw przejawia się jako zasada dołączania do nazwy zdalnej procedury znaku podkreślenia i numeru wersji w przypadku procedury klienta oraz znaku podkreślenia, numeru wersji i członu „svc" w przypadku procedury serwera. Odgałęzienie else dyrektywy preprocesora zawiera podobne definicje, ale przeznaczone dla środowisk nie korzystających ze standardowych prototypów funkcji C. Jeżeli opcja -c nie zostałaby użyta, wynikowy plik nagłówkowy zawierałby tylko jeden prototyp funkcji printjhello, a mianowicie print_hello_l.
Zanim zgłębimy utworzone przez program rpcgen procedury wejścia serwera i klienta, zastanówmy się, jak podzielić pierwotny program na składnik kliencki i serwerowy. Po podziale i zastosowaniu narzędzia rpcgen uzyskamy sześć plików (patrz ilustracja 9.9).
użytkownik pisze program rpcgen generuje z niego
proces-klient
proces-serwer
Ilustracja 9.9. Pliki i zależności typu klient-serwer
1 Choć komentarz jest napisany dość czupumie, nie odbiega daleko od prawdy (warto się o tym przekonać)!
Zaczniemy od pisania klienta. Jak w wyjściowym programie, klient będzie wywoływał funkcję print_hello. Jednak w naszej konfiguracji funkcja print_hello powinna być funkcją lokalną ulokowaną w osobnym programie (jest to program hello client. c pokazany poniżej jako program 9.3).
t*
* Program-KLIENT: hello_client.c
* Ten kod klienta będzie wykonywany przez proces lokalny.
*/
łinclude <stdio.h> tinclude <stdlib.h>
łinclude "hello.h" /* wygenerowany przez rpcgen na podstawie hello.x ”,
void main(int argc, char *argv[]) 1 CLIENT "Client;
int *return_value, filier;
char *server;
/*
* Trzeba podać nazwę hosta, w którym będzie uruchomiony program.
* Nazwę można uzyskać z pierwszego argumentu linii poleceń.
*/
if (argc != 2) {
fprintf(stderr, "Składnia: %s nazwa_hosta\n", *argv); exit<l);
server = a rqv[1];
/*
* generowanie uchwytu klienta */
if ((Client = clnt_create(server, DISPLAYPRG, DXSPLAY_VER, "visible")) == (CLIENT *) NULL) ( clnt^pcreateerror(server);
}
return_value = print^hello^l((yoid *) sfiller, Client); if (*return_value)
printf ("Misja spełnióna\n"); else
printf("Nie udało się\n"); exit (0);
Choć spora porcja kodu jest podobna do oryginalnego programu, wprowadzone zostały pewne zmiany dostosowujące go do zdalnego wykonywania procedur. Przyjrzyjmy się im punkt po punkcie. Dołączono dwa dodatkowe odwołania do plików nagłówkowych. Klient będzie korzystał z wywołania systemowego exit, dlatego należało włączyć plik <stdlib. h> zawierający jego prototyp. Drugim włączanym plikiem jest hel lo. h, plik utworzony przez rpcgen (jego zawartość już została omówiona). Zakłada się, że plik ten rezyduje lokalnie. . •
W tym przykładzie będziemy przekazywać dane z linii poleceń do funkcji main programu klienta, dlatego parametr void został zastąpiony standardowymi argumentami argc
257