Transcript 09.RPC

Jarosław Kuchta
Programowanie Współbieżne
Zdalne wywołania
procedur
[email protected]
[email protected]
Podstawy





RPC – Remote Procedure Call
Wywołanie procedur jednego procesu z innego
procesu.
Proces wywoływany – serwer
Proces wywołujący - klient
Wywoływana procedura jest wykonywana w
przestrzeni adresowej wywoływanego procesu
(serwera).
RPC
2
RPC w sieci




protokół opracowany przez firmę Sun
popularny w systemie Unix
obsługiwany w bibliotekach języka Java
współcześnie obsługiwany przez protokoły:
SOAP
 CORBA
 XML-RPC
 JSON-RPC

RPC
3
XDR – External Data
Representation



standard jednolitej reprezentacji danych
w sieci między komputerami o różnych architekturach
warunki podstawowe




wszystkie typy danych mają rozmiar będący wielokrotnością
4 bajtów,
liczby całkowite kodowane w standardzie BigEndian
(najpierw starsze bajty)
liczby rzeczywiste w formacie IEEE.
nadawca i odbiorca muszą znać struktury danych (nie są
przekazywane)
RPC
4
Filtry XDR




xdr_int
xdr_float
xdr_char
xdr_wrapstring (dla typu char *)
RPC
5
Filtry XDR dla struktur

struktura


struct s { int i, float x }
filtr
int xdr_s (XDR *xptr, struct s *sptr)
{ return (xdr_int(xptr, &sptr->i) &&
xdr_float(xptr, &sptr->x); }

RPC
6
Identyfikacja procedury

trzy liczby całkowite:
numer programu
 numer wersji
 numer procedury

RPC
7
Rejestracja procedury

int registerrpc(
unsigned long PROG,
 unsigned long VERS,
 unsigned long PROC,
 char * ( * proc)(), // adres procedury
 int (* xdr_arg)(), // adres filtra argumentów
 int (* xdr_res)()); // adres filtra wyników

RPC
8
Przykład – procedura
udostępniająca czas systemowy
#include <rpc/rpc.h>
void main (void)
{
registerrpc (
PRZYKŁAD, WERSJA, CZAS,
czas, xdr_void, xdr_t);
svc_run();
}
#define PRZYKLAD 0x20000000
#define WERSJA 1
#define CZAS 1
typedef struct { … } tt;
extern void podaj_czas (tt *) { … }
char *czas (void)
{
static tt t;
podaj_czas (&t);
return (char *)&t;
}
RPC
9
Wywołanie procedury zdalnej

int callrpc(
char *server, // nazwa serwera
 unsigned long PROG,
 unsigned long VERS,
 unsigned long PROC,
 int (* xdr_arg)(),
 char *arg, // struktura argumentów
 int (* xdr_res)(),
 char *res); // struktura wyników

RPC
10
Przykład – wywołanie procedury
udostępniającej czas systemowy
#include <rpc/rpc.h>
void main (void)
{
tt t;
#define PRZYKLAD 0x20000000
#define WERSJA 1
#define CZAS 1
typedef struct { … } tt;
callrpc("servername",
PRZYKŁAD, WERSJA, CZAS,
xdr_void, NULL, xdr_t, &t);
int xdr_t (XDR *xptr, tt *tp) { … }
korzystaj (&t);
}
extern void korzystaj (tt *);
RPC
11
RPC a wykonanie równoległe
zwykłe wywołanie RPC
main
wywołanie przez rozgłaszanie
proc
main
proc
registerrpc
proc
registerrpc
callrpc
clnt_broadcast
proces wywołujący jest wstrzymywany
procesy wywoływane są równolegle
RPC
12
Wykonanie równoległe
– przez rozgłaszanie

int clnt_broadcast(
unsigned long PROG,
 unsigned long VERS,
 unsigned long PROC,
 int (* xdr_arg)(),
 char *arg,
 int (* xdr_res)(),
 char *res,
 int (* res_proc)());

RPC
13
Przykład – wywołanie procedury
przez rozgłaszanie
#include <rpc/rpc.h>
void main (void)
{
tt t;
#define PRZYKLAD 0x20000000
#define WERSJA 1
#define CZAS 1
clnt_broadcast(
PRZYKŁAD, WERSJA, CZAS,
xdr_void, NULL, xdr_t, &t,
po_rozgloszeniu);
typedef struct { … } tt;
int xdr_t (XDR *xptr, tt *tp) { … }
korzystaj (&t);
extern void korzystaj (tt *);
}
int po_rozgloszeniu (char *t, struct
socketaddr_in *addr)
{
return true;
}
RPC
14
Ograniczenia

Brak mechanizmu wstrzymywania procesów



w Unix RPC – blokowanie procesu
wywoływanego
konieczność jawnego podawania nazwy serwera


rozwiązanie: wysokopoziomowe mechanizmy
synchronizacji
rozwiązanie: rpc_bind
zdalne rozgłaszanie – przynajmniej jedna
procedura musi być wykonywana
RPC
15
Asynchroniczne RPC –
deklaracja procedury (IDL)
[ uuid (7f6c4340-eb67-11d1-b9d7-00c04fad9a3b), version(1.0),
pointer_default(unique) ]
interface AsyncRPC
{
const long DEFAULT_ASYNC_DELAY = 10000;
const short APP_ERROR = -1;
const char* DEFAULT_PROTOCOL_SEQUENCE = "ncacn_ip_tcp";
const char* DEFAULT_ENDPOINT = "8765";
void NonAsyncFunc(handle_t hBinding, [in, string] unsigned char * pszMessage);
void AsyncFunc(handle_t hBinding, [in] unsigned long nAsychDelay);
void Shutdown(handle_t hBinding);
}
RPC
16
IDL


IDL – Interface Description Language
MIDL – kompilator IDL
RPC
17
Alternatywa – atrybuty ACF
ACF – Application Configuration File
 IDL + ACF:
interface AsyncRPC
{
[async] AsyncFunc();
}

RPC
18
Wywołanie asynchroniczne (1)
RPC_ASYNC_STATE Async;
RPC_STATUS status;
// Initialize the handle.
status = RpcAsyncInitializeHandle(&Async, sizeof(RPC_ASYNC_STATE));
if (status)
{
// Code to handle the error goes here.
}
Async.UserInfo = NULL;
Async.NotificationType = RpcNotificationTypeEvent;
Async.u.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (Async.u.hEvent == 0)
{
// Code to handle the error goes here.
}
RPC
19
Wywołanie asynchroniczne (2)
// Call an asynchronous RPC routine here
RpcTryExcept
{
printf("\nCalling the remote procedure 'AsyncFunc'\n");
AsyncFunc(&Async, AsyncRPC_ClientIfHandle, nAsychDelay);
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("AsyncFunc: Run time reported exception 0x%lx = %ld\n", ulCode,
ulCode);
}
RpcEndExcept
RPC
20
Wywołanie synchroniczne tej
samej procedury
// Call a synchronous routine while the asynchronous procedure is still running
RpcTryExcept
{
printf("\nCalling the remote procedure 'NonAsyncFunc'\n");
NonAsyncFunc(AsyncRPC_ClientIfHandle, pszMessage);
fprintf(stderr, "While 'AsyncFunc' is running asynchronously,\n"
"we still can send message to the server in the mean time.\n\n");
}
RpcExcept(1)
{
ulCode = RpcExceptionCode();
printf("NonAsyncFunc: Run time reported exception 0x%lx = %ld\n",
ulCode, ulCode);
}
RpcEndExcept
RPC
21
Oczekiwanie na odpowiedź
bez blokowania własnego wątku:
// This code fragment assumes that Async is a valid asynchronous RPC handle.
if (WaitForSingleObject(Async.u.hEvent, INFINITE) == WAIT_FAILED)
{
RpcRaiseException(APP_ERROR);
}


z blokowaniem własnego wątku:
if (SleepEx(INFINITE, TRUE) != WAIT_IO_COMPLETION)
{
RpcRaiseException(APP_ERROR);
}
RPC
22
Obsługa wywołania przez serwer
(1)
void AsyncFunc(IN PRPC_ASYNC_STATE pAsync,
IN RPC_BINDING_HANDLE hBinding,
IN OUT unsigned long nAsychDelay)
{
int nReply = 1;
RPC_STATUS status;
unsigned long nTmpAsychDelay;
int i;
if (nAsychDelay < 0)
nAsychDelay = DEFAULT_ASYNC_DELAY;
else if (nAsychDelay < 100)
nAsychDelay = 100;
RPC
23
Obsługa wywołania przez serwer
(2)
// We only call RpcServerTestCancel if the call
// takes longer than ASYNC_CANCEL_CHECK ms
if (nAsychDelay > ASYNC_CANCEL_CHECK)
{
nTmpAsychDelay = nAsychDelay/100;
for (i = 0; i < 100; i++)
{
Sleep(nTmpAsychDelay);
if (i%5 == 0)
{
fprintf(stderr,
"\rRunning AsyncFunc (%lu ms) (%d%c) ... ",
nAsychDelay, i+5, PERCENT);
status = RpcServerTestCancel(
RpcAsyncGetCallHandle(pAsync));
if (status == RPC_S_OK)
{
fprintf(stderr,
"\nAsyncFunc has been canceled!!!\n");
break;
}
else if (status != RPC_S_CALL_IN_PROGRESS)
{
printf("RpcAsyncInitializeHandle returned
0x%x\n", status);
exit(status);
}
}
}
}
else
Sleep(nAsychDelay);
RPC
24
Wysłanie odpowiedzi przez
serwer
printf("\nCalling RpcAsyncCompleteCall\n");
status = RpcAsyncCompleteCall(pAsync, &nReply);
printf("RpcAsyncCompleteCall returned 0x%x\n", status);
if (status)
exit(status);
}
RPC
25
Przyjęcie odpowiedzi przez
klienta
status = RpcAsyncCompleteCall(
&Async, &Reply);
// W tym momencie wynik jest zwracany w Reply
RPC
26