clnttcp_create
, clnttcp_call
clntudp_bufcreate
, clntudp_call
typedef struct __client { AUTH *cl_auth; struct clnt_ops { /* wywolanie zdalnej procedury */ enum clnt_stat (*cl_call)(); /* przerwanie wolania procedury */ void (*cl_abort)(); /* pobiera kod bledu */ void (*cl_geterr)(); /* zwalnia pamiec rezultatow */ bool_t (*cl_freeres)(); /* usuwa strukture klienta */ void (*cl_destroy)(); /* operacja ioctl() */ bool_t (*cl_control)(); } *cl_ops; caddr_t cl_private; - dane prywatne klienta (zalezne od protokolu) } CLIENT;
cl_auth
- dane do identyfikacji klientaclnt_ops
- operacje klienta, wskazniki na funkcje zalezne od protokolucl_abort
- w przypadku obu klientow (TCP, UDP) zmienna ta wskazuje na pusta funkcje. Prawdopodobnie funkcja przewidziana dla innych, niestandardowych protokolow.cl_freeres
- funkcja powinna wywolac filtr XDR dla rezultatow z operacja XDR_FREEcl_control
- funkcja umozliwiajaca sprawdzenie/ustawienie czasu czekania na odowiedz i pobrania adresu sieciowego serwera
struct ct_data { int ct_sock; struct sockaddr_in ct_addr; char ct_mcall[MCALL_MSG_SIZE]; XDR ct_xdrs; [...] };
ct_sock
- gniazdo klientact_addr
- adres serweract_mcall
- zakodowany standardowy fragment naglowkact_xdrs
- potok komunikatow XDR
Tworzeniem klienta zajmuje sie funkcja:
CLIENT* clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, u_int sendsz, u_int recvsz)
raddr
- adres zdalny lub NULL
prog, vers
- identyfikuja program na serwerze
sockp
- wczesniej utworzone gniazdo lokalne lub -1 jesli procedura ma utworzyc nowe
sendsz, recvsz
- wielkosci buforow TCP
bindresvport()
), czyli zastrzezony dla root'a. Dla zwyklego uzytkownika bindresvport()
zwroci kod bledu, jednak rezultat jej nie jest w ogole sprawdzany ani zapamietywany.
connect()
; jesli nie udalo sie wczesniej przypisac numeru portu to connect()
robi to automatycznie stosujac funkcje autobind()
), ktore jest zamykane dopiero przez clnttcp_destroy()
.
clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout);
rm_xid
w zakodowanym fragmencie naglowka(!!!), stad kazda wiadomosc ma unikalny (do pewnego stopnia) identyfikator. Operacja:u_long *msg_x_id = (u_long *)(ct->ct_mcall);
--(*msg_x_id);
x_id
(zazwyczaj wystarczy jeden raz).
accepted_reply
: AR_results.where
i AR_results.proc
na adres bufora i funkcje rozkodowujaca rezultat, funkcja sprawdza poprawnosc rezultatow (tzn. czy procedura zostala wykonana i tozsamosc nadawcy) i rozkodowuje rezultaty wprost pod adres wskazany przez uzytkownika przy wywolaniu funkcji.
clnttcp_geterr, clnttcp_freeres, clnttcp_abort, clnttcp_control, clnttcp_destroy
) sa bardzo proste, a ich dzialanie powinno byc oczywiste.
struct cu_data { int cu_sock; struct sockaddr_in cu_raddr; XDR cu_outxdrs; u_int cu_sendsz; u_int cu_recvsz; char *cu_outbuf; char *cu_inbuf; [...] };
cu_sock
- gniazdo klientacu_raddr
- adres serweracu_outxdrs
- potok XDRMEMcu_sendsz
- rozmiar bufora wyjsciowegocu_recvsz
- rozmiar bufora wejsciowegocu_outbuf
- adres bufora wyjsciowegocu_inbuf
- adres bufora wejsciowego
Warto wspomniec, ze powyzsza struktura oraz bufory wejsciowy i wyjsciowy znajduja sie w jednym bloku pamieci o rozmiarze sizeof(struct cu_data)+cu_sendsz+cu_recvsz
, ktory jest pobierany jednym wywolaniem funkcji malloc
.
CLIENT* clntudp_bufcreate(struct sockaddr_in *raddr, u_long prog, u_long vers, struct timeval wait, int *sockp, u_int sendsz, u_int recvsz)
Funkcja powyzsza jest wywolywana z jednolinijkowej funkcji clntudp_create(raddr, prog, vers, wait, sockp)
, ktora ustawia standardowe wartosci sendsz
i recvsz
.
Dzialanie jest podobne jak w przypadku TCP przed wywolaniem funkcji connect()
.W tym przypadku nie nawiazuje sie polaczenia. Funkcja tworzy potok XDRMEM, ktorym koduje poczatek naglowka i zapamietuje ten potok.
clntudp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout)
rm_xid
w zakodowanym fragmencie naglowka (w TCP bylo zmiejszane, ale i tak nie ma to znaczenia).
sendto()
wysyla serwerowi wiadomosc, ustawia pola w accepted_reply
: AR_results.where
i AR_results.proc
na adres bufora i funkcje rozkodowujaca rezultat.
select()
. Jesli po ustalonym czasie odpowiedz nie nadejdzie to ponawiane jest wysylanie (jak kilka razy nie otrzyma sie dpowiedzi to zwracany jest blad).
recvfrom()
) i jesli jego identyfikator x_id
jest niezgodny z wyslanym przez klienta to dalej nasluchuje sie (porownanie to nie wymaga rozkodowania wiadomosci, gdyz w pamieci jest trzymany zakodowany identyfikator w naglowku komunikatu od klienta do serwera).
Tak jak w TCP: pozostale funkcje (clntudp_geterr, clntudp_freeres, clntudp_abort, clntudp_control, clntudp_destroy
) sa bardzo proste.
int callrpc(char *host, u_long prognum, u_long versnum, u_long procnum, xdrproc_t inproc, char *in, xdrproc_t outproc, char *out)
,
ktora sama tworzy klienta RPC (tylko dla protokolu UDP) i wywoluje clntudp_call
. Na koniec dzialania tej funkcji struktura klienta nie jest usuwana i moze byc ponownie uzyta przy ponownym wywolaniu funkcji. Usuwana jest dopiero przy wywolaniu funkcji z innym serwerem, numerem programu lub wersji. Implementacja: plik rpc/clnt_simple.c
./rpc/*
- implementacja RPC
/usr/include/rpc/*
/usr/info/libc.info
- opis funkcji dotyczacych gniazd