Komunikacja między procesami w Unixie
Jeżeli proces zostanie uruchomiony lokalnie, zostanie również wywołany klient, który otrzyma (w postaci parametrów) nazwę bieżącej staq'i roboczej. Wtedy na ekranie znajdą się następujące informacje:
morpheus % Client morpheus Misja spełniona
Co ciekawe, program-klient wyświetlił komunikat „Misja spełniona", ale nie wyświetlił komunikatu „Cześć, ludzie!Rozwiązanie tej tajemnicy ma związek z urządze-nieię terminala skojarzonego ze standardowym wyjściem programu-serwera. Jak widać na ilustracji 9.13, zamiast urządzenia wyjściowego procesu-serwera została wyświetlona pozycja oznaczająca brak urządzenia. Świadczy to, że dane wyjściowe z serwera trafiają w próżnię. Problem można skorygować na kilka sposobów. Wynik z serwera można wysłać explicite na konsolę. Aby zaimplementować takie rozwiązanie, należy w programie otworzyć za pomocą funkcji fopen plik (urządzenie) /dev/console, po czym wyświetlić wynikowe dane na konsoli, używając funkcji fprintf z uzyskanym w ten sposób wskaźnikiem na zmienną typu FILE jako parametrem. Niestety z takim rozwiązaniem wiąże się pewien kłopot: użytkownik może nie mieć dostępu do urządzenia konsoli. W takiej sytuacji funkcja fopen okaże się nieskuteczna. Innym sposobem jest przekazanie urządzenia konsoli procesu klienta do serwera w postaci pierwszego parametru zdalnej procedury. Być może okaże się to rozwiązaniem trochę lepszym, ale wciąż nieskutecznym w przypadku, gdy procesy klienta i serwera znajdują się w różnych staąach roboczych (a tym samym dysponują różnymi urządzeniami). Trzecia metoda to napisanie serwera przekazującego komunikat z powrotem do klienta, który będzie go lokalnie wyświetlał.
Choć nasza apłikaąa typu klient-serwer wymaga jeszcze kilku drobnych szlifów, już teraz możemy ją przetestować w środowisku rozproszonym (w którym serwer i klient działają na różnych staq'ach roboczych). Jeżeli obie stacje robocze są homogeniczne (czyli jeżeli działa w nich ten sam system operacyjny), to możemy osiągnąć założony cel, wydając polecenie podobne do tego z ilustracji 9.15.
morpheus % server
morpheus % rsh obiwan $cwd/client morpheus Misja spełniona
W powyższym przykładzie uruchamiamy program-serwer, pracując na stacji morpheus. Następnie, korzystając z polecenia zdalnej powłoki, rsh, uruchamiamy program-klient na stacji obiwan. Ponieważ katalog, w którym znajdują się programy aplikacji, nie jest wpisany do standardowego łańcucha ścieżek przeszukiwanych przez system, musimy przekazać jego nazwę (zapisaną w zmienną systemowej cwd) staqi roboczą, posługując się parametrami.1
Tak więc w naszym przykładzie program klienta będzie uruchomiony na stacji roboczej obiwan. Klientowi przekazywana jest nazwa stacji roboczej serwera, morpheus. Jak pokazano, proces klienta, działający na hoście obiwan, żąda z powodzeniem od stacji morpheus uruchomienia funkcji print_hello. Komunikat „Cześć, ludzie!" nadal nie jest wyświetlany, jak w poprzednim przykładzie (i z tego samego powodu). Przyjrzyjmy się również dwóm procedurom wejścia RPC, wygenerowanym przez rpc-gen. Plik hello_clnt. c jest stosunkowo niewielki (patrz ilustracja 9.16). Zawiera wywołanie funkcji print_hello_l.
W poniższym programie użyto funkcji bibliotecznej ttyname wyświetlającej nazwę urządzenia wyjściowego skojarzonego z plikiem stdout.
łinclude <stdio.h> łinclude <stdlib.h> main (void) (
char *dev = ttyname(fiłeno(stdout)); if (dev)
printf("Urządzenie standardowego wyjścia (stdout): %s\n", dev); else
fprintf(stderr, "Urządzenie standardowego wyjścia (stdout) nieznane!\n");
Zmień programy klienta i serwera tak, aby urządzenie standardowego wyjścia skojarzone z plikiem stdout było wykrywane przez klienta i przekazywane do serwera w postaci pierwszego argumentu funkcji print_hello. Serwer otworzy urządzenie w trybie zapisu, aby wyświetlić komunikat „Cześć, ludzie! ".Wskazówka: nazwa urządzenia wyjściowego musi być zapisana jako tablica znaków, aby mogła zostać przekazana do serwera. Argument void w pliku definiującym protokół musi być zmieniony, aby wskazywał, iż przekazywanym argumentem jest tablica znakowa. W definicji typu nie można jednak użyć wyrażenia char *, ponieważ nie jest ono jednoznaczne — może oznaczać wskaźnik na jeden znak lub na całą tablicę. W języku RPC do definiowania tablicy znaków zakończonej znakiem NULL służy typ string.
/*
* Proszę nie modyfikować tego pliku.
* Został on wygenerowany przez rpcgen.
*/
łinclude <memory.h> /* dla funkcji memset */
łinclude "hello.h"
/* domyślny timeout można zmienić /* za pomocą dnt_control () */ static struct timeval TIMEOUT = { 25, 0 );
265
Zamiast zmiennej $swd do uzyskania bieżącego katalogu roboczego można użyć wyniku działania polecenia pwd. Jednakże sięganie do zmiennych jest bardziej efektywne niż uruchamianie poleceń.