Komunikacja między procesami w Unixle
łinclude "hello.h* /* wygenerowany przez rpcgen na podstawie hello.x */
int * print_hello_l_svc(void * filier, struct svc_req * req) { static int ok;
ok “ printf ("Cześć, ludzie !\n"); return (Sok);
Serwer zawiera funkcję print_hello. Jak widać, dodano do niej kilka elementów i kilka zmodyfikowano, aby uzyskać zdalnie wykonywaną procedurę. Po pierwsze, jak wspomniano podczas omawiania programu klienta, funkcja print_hello zwraca teraz wskaźnik na liczbę całkowitą, a nie samą liczbę całkowitą. W tym przykładzie zwracany adres jest skojarzony z identyfikatorem ok. Identyfikator ten jest zadeklarowany jako klasy static. Zwracany identyfikator musi być statyczny, a nie lokalny. Lokalne identyfikatory są umieszczane na stosie, a więc odwołania do nich za pomocą wskaźników po zakończeniu działania funkcji mogą stać się nieprawidłowe. Do nazwy funkcji dodano znaki _1 (numer wersji). Ponieważ w wywołaniu rpcgen użyto opqi -c, do nazwy funkcji dodany został również pomocniczy sufiks _svc. Całym tym zamieszaniem z nazwami nie warto się zbytnio przejmować. Odwzorowanie funkcji print_hello_l z programu klienta w funkcję print_hello_l_svc w programie serwera odbywa się za sprawą kodu procedury wejścia hello_svc. c generowanej przez rpcgen. Argument przekazany do print_hel-lo jest wskaźnikiem. W razie potrzeby w strukturze, na którą on wskazuje, można umieścić wiele różnych elementów (i w ten sposób przekazać wiele parametrów). W nowszych wersjach rpcgen dostępna jest opcja -N, która umożliwia obsługę wielu argumentów procedur RPC, jeśli argumenty te mają być przekazywane przez wartość, a nie przez referencję, lub jeśli przez procedura RPC ma zwracać wartość, a nie wskaźnik. Dodany jest drugi argument, struct svc_req *req, który będzie zawierał dane wywołania. Najpierw należy skompilować program klienta. Kiedy w proces zaangażowanych jest tylko kilka plików, najlepiej spisuje się prosta sekwencja kompilacyjna z linii poleceń. W dalszej części tekstu zajmiemy się również przygotowywaniem skryptu dla programu make, automatyzującego proces kompilacji. Do kompilatora przekazuje się nazwy dwóch plików klienta, hello_client. c (który został napisany) i hello clnt. c (który został wygenerowany przez rpcgen). Chcemy, aby kod wykonywalny został zapisany w pliku o nazwie client. Ponieważ w plikach z kodem źródłowym znajdują się odwołania do funkq'i z biblioteki sieciowej, należy przekazać libnsl do opcji -libnsl. Na ilustracji 9.11 pokazano dokładną postać polecenia kompilującego.
% CC hello_client.c helloclnt.c -o Client -Insi
hello_client.c:
hello_clnt.c:
Kompilując serwer, stwierdzimy, że kompilator generuje liczbę ostrzeżenia (patrz ilu-stracja 9.12). Są to cenne wskazówki umożliwiające usprawnienie programu (pozwalają na przykład wykryć zadeklarowane, ale nie wykorzystywane identyfikatory itp.), jednak nie wstrzymujące kompilacji i nie wykluczające utworzenia kodu wykonywalnego. Jeśli posłużymy się kompilatorem gcc, który jest mniej restrykcyjny, nie otrzymamy żadnych ostrzeżeń.
% CC hello_server.c hello_svc.c -o server -Insi hello_server.c:
*hello_server , linę 10: warning: filier not used
"hello_server.c", linę 10: warning: req not used
hello_svc.c:
"hello_svc.c", linę 70: warning: rlim^t assigned to int
"hello svc.c", linę 55: warning: sig not used
"hello svc.c", linę 195: warning: rlim_t assigned to int
"hello svc.c", linę 32: warning: ::_rpcpmstart defined but not used
Czy zmienna filier jest rzeczywiście potrzebna? Spróbuj umieścić w komentarzu odwołania do niej w programie hello_client. c i he 1 lo_server. c. Zmodyfikuj plik z definicją protokołu, hello. x. Uruchom rpcgen i skompiluj wszystkie zmienione składniki. Co się dzieje? Dlaczego?
Zmień program serwera aplikacji hello tak, aby serwer usuwał się, jeśli będzie niewykorzystywany przez określony czas (na przykład pięć minut). Używając wywołania systemowego signal, połącz odebranie alarmu (alarm) z funkcją kończącą. Aby wykonać to zadanie, należy umieścić nowe elementy kodu zarówno w pliku hello_server. c, jak i w hello_svc. c.
Najpierw przetestujemy program, uruchamiając zarówno proces klienta, jak i serwer na tej samej stacji roboczej. Zaczniemy od wywołania serwera, czyli wpisania jego nazwy w linii poleceń. Proces serwera zostanie automatycznie umieszczony w tle, a to za sprawą użytego znaku Proste polecenie ps pozwoli nam sprawdzić, czy rzeczywiście serwer już działa (patrz ilustracja 9.13).
% server
% ps -ef | grep server
gray 9274 8022 5 08:40:54 term/2 0:00 grep server
gray 9267 1 26 08:40:44 ? 0:00 server
Polecenie ps informuje, iż proces-serwer, w tym przypadku o identyfikatorze równym 9267, rzeczywiście znajduje się w pamięci. Jego procesem nadrzędnym jest proces o identyfikatorze 1 (init), a wyświetlone urządzenie terminala to „?", co oznacza brak takiego urządzenia. Proces pozostaje w pamięci nawet wówczas, gdy wyloguje się użytkownik, który go uruchomił. Podczas pisania i testowania programów RPC użytkownik powinien pamiętać o tym, aby przed wylogowaniem usunąć niepotrzebne procesy serwerów RPC.
263