Size: 6295
Comment:
|
← Revision 3 as of 2009-05-21 13:46:24 ⇥
Size: 5031
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 3: | Line 3: |
--('''~+{{{class NtkRPCDispatcher(object)}}}+~''')-- '''~+{{{class RPCDispatcher(object)}}}+~''' | '''~+{{{class RPCDispatcher(object)}}}+~''' |
Line 5: | Line 5: |
Un'istanza della classe RPCDispatcher --(registra con il metodo register_function le funzioni (indicizzandole per nome) e)-- fornisce il metodo '''{{{marshalled_dispatch(data)}}}''' per richiamare le funzioni definite remotable sulla base di un blob (arrivato via rete) che codifica (tramite rencode - vedi il [[../ModuloRencode|modulo rencode]]) nome-funzione e parametri. | Un'istanza della classe RPCDispatcher fornisce il metodo '''{{{marshalled_dispatch(data)}}}''' per richiamare le funzioni definite remotable sulla base di un blob (arrivato via rete) che codifica (tramite rencode - vedi il [[../ModuloRencode|modulo rencode]]) nome-funzione e parametri. |
Line 7: | Line 7: |
Lato server è sufficiente che le funzioni abbiano il nome in [[../ElencoRemotableFunctions|remotable_funcs]] (--(nelle globals o)-- in una classe di cui sono metodo) --('''~+{{{SocketServer.BaseRequestHandler}}}+~''')-- --(Base class for request handler classes. <<BR>> This class is instantiated for each request to be handled. The constructor sets the instance variables request, client_address and server, and then calls the handle() method. To implement a specific service, all you need to do is to derive a class which defines a handle() method. <<BR>> The '''handle'''() method can find the request as self.request, the client address as '''self.client_address''', and the server (in case it needs access to per-server information) as self.server. Since a separate instance is created for each request, the handle() method can define arbitrary other instance variariables.)-- --('''~+{{{SocketServer.TCPServer (SocketServer.BaseServer)}}}+~''')-- --(Base class for various socket-based server classes. <<BR>> Defaults to synchronous IP stream (i.e., TCP). <<BR>> Methods for the caller:)-- * --({{{__init__(server_address, RequestHandlerClass)}}})-- * --({{{serve_forever()}}})-- --('''~+{{{class StreamRequestHandler(SocketServer.BaseRequestHandler)}}}+~''' <<BR>> '''~+{{{class TCPServer(SocketServer.TCPServer, RPCDispatcher)}}}+~''')-- --(La classe '''{{{StreamRequestHandler}}}''' ereditando {{{BaseRequestHandler}}} fornisce un hook nel metodo '''{{{handle()}}}''' per gestire una richiesta. Viene overridato per a) popolare la classe '''{{{CallerInfo}}}''' con i dati del chiamante e b) richiamare la marshalled_dispatch del server passando questi dati. <<BR>> La classe '''{{{TCPServer}}}''' eredita sia da {{{TCPServer}}} sia da {{{RPCDispatcher}}} e nel suo costruttore usa come gestore predefinito {{{StreamRequestHandler}}}. In questo modo quando si crea una istanza - e.g. {{{server = TCPServer(ntkd, ('localhost', 8888))}}} - si ha un server che permette di richiamare funzioni quando viene ricevuta una richiesta (metodo '''{{{handle}}}'''). <<BR>> Inoltre si ha un indirizzo predefinito che è ('localhost', 269) - quindi si può usare {{{server = TCPServer(ntkd)}}} - ascolta tutto sulla 269.)-- |
Lato server è sufficiente che le funzioni abbiano il nome in [[../ElencoRemotableFunctions|remotable_funcs]] (in una classe di cui sono metodo) |
Line 41: | Line 13: |
Si istanzia un {{{RPCDispatcher}}} e poi sta in ascolto su un socket "stackless-wrapped", di default bindato alla porta 269 di tutte le interfacce di rete. Per ogni connessione che riceve richiama la microfunc '''{{{micro_stream_request_handler}}}''' e subito torna in ascolto. | Si istanzia un {{{RPCDispatcher}}} e poi sta in ascolto su un socket "stackless-wrapped" (vedi il [[../ModuloMicrosock|modulo microsock]] per le operazioni di I/O in ambiente stackless), di default bindato alla porta 269 e non associato ad una specifica interfaccia di rete. Per ogni connessione che riceve richiama la microfunc '''{{{micro_stream_request_handler}}}''' e subito torna in ascolto. |
Line 45: | Line 17: |
--('''~+{{{class FakeNtkd()}}}+~''')-- '''~+{{{class FakeRmt()}}}+~''' | {{{MicroTCPServer}}} è una microfunc, quindi si avvia in un microthread e resta sempre in vita. Viene però fornito un metodo {{{stop_tcp_servers}}} nel modulo RPC che permette di fermare il server. '''~+{{{class FakeRmt()}}}+~''' |
Line 55: | Line 29: |
class TCPClient(FakeRmt) Semplice classe client che eredita da FakeRmt. Si usa tipo: a = TCPClient('192.168.1.1',8888) ret = a.rpc_call('nomefunc', (1,)) ret = a.nomefunc(1) Funziona a patto che il blob prodotto da rencode per nomefunc e parametri non superi 1024 bytes e lo stesso per il valore ritornato. Alla chiamata di un metodo, si collega al MicroTCPServer remoto, invia in un blob il nome del metodo e gli argomenti, aspetta la risposta in un blob dal host remoto, la decodifica (la risposta può essere anche una eccezione) e la resituisce, terminando, al chiamante. |
'''~+{{{class TCPClient(FakeRmt)}}}+~''' |
Line 63: | Line 31: |
Semplice classe client che eredita da {{{FakeRmt}}}. Si usa tipo: <<BR>> {{{ a = TCPClient('192.168.1.1',8888)}}} <<BR>> --({{{ ret = a.rpc_call('nomefunc', (1,))}}})-- <<BR>> {{{ ret = a.nomefunc(1)}}} <<BR>> Alla chiamata di un metodo, si collega al {{{MicroTCPServer}}} remoto, invia in un blob il nome del metodo e gli argomenti, aspetta la risposta in un blob dal host remoto e la decodifica (la risposta può essere anche una eccezione). Poi il metodo termina restituendo la risposta al chiamante. |
|
Line 64: | Line 41: |
Le microfunc micro_dgram_request_handler e UDPServer sono le analoghe di micro_stream_request_handler e TCPServer in versione UDP broadcast. La MicroUDPServer viene richiamata passando la root_instance. Si istanza un RPCDispatcher e poi riceve i pacchetti (recvfrom(8192)) da un socket "stackless-wrapped" di tipo datagram, di default bindato alla porta 269 di tutte le interfacce di rete. Con ogni pacchetto che riceve richiama la microfunc micro_dgram_request_handler e subito torna in ascolto. Questa microfunc a) popola la classe CallerInfo con i dati del chiamante, b) decodifica il pacchetto con _data_unpack_from_buffer, c) richiama la marshalled_dispatch del RPCDispatcher passando il blob e il CallerInfo. |
'''~+{{{MicroUDPServer(...)}}}+~''' |
Line 68: | Line 43: |
class BcastClient(FakeRmt) Semplice classe client analoga di TCPClient in versione UDP broadcast. La classe BcastClient si usa tipo: a = BcastClient() # si può passare un elenco di interfacce a.nomeFunc(3,2) # nulla viene ritornato |
Le microfunc '''{{{micro_dgram_request_handler}}}''' e '''{{{MicroUDPServer}}}''' sono le analoghe di {{{micro_stream_request_handler}}} e {{{MicroTCPServer}}} in versione UDP broadcast. <<BR>> Diversamente dalla {{{MicroTCPServer}}}, la '''{{{MicroUDPServer}}}''' viene richiamata ''n'' volte, una per ogni interfaccia di rete. <<BR>> La '''{{{MicroUDPServer}}}''' viene richiamata passando la root_instance e l'interfaccia di rete. Si istanzia un {{{RPCDispatcher}}} e poi riceve i pacchetti (''{{{recvfrom(8192)}}}'') da un socket "stackless-wrapped" di tipo datagram, di default bindato alla porta 269 e associato alla specifica interfaccia di rete. Con ogni pacchetto che riceve richiama la microfunc '''{{{micro_dgram_request_handler}}}''' e subito torna in ascolto. <<BR>> Questa microfunc a) popola la classe '''{{{CallerInfo}}}''' con i dati del chiamante, b) decodifica il pacchetto con '''{{{_data_unpack_from_buffer}}}''', c) richiama la {{{marshalled_dispatch}}} del {{{RPCDispatcher}}} passando il blob e il {{{CallerInfo}}}. {{{MicroUDPServer}}} è una microfunc, quindi ogni sua chiamata (una per interfaccia di rete) si avvia in un microthread e resta sempre in vita. Viene però fornito un metodo {{{stop_udp_servers}}} nel modulo RPC che permette di fermare tutti i servers udp avviati. '''~+{{{class BcastClient(FakeRmt)}}}+~''' Semplice classe client analoga di {{{TCPClient}}} in versione UDP broadcast. <<BR>> La classe {{{BcastClient}}} si usa tipo: <<BR>> {{{ a = BcastClient() # si può passare un elenco di interfacce}}} <<BR>> {{{ a.nomeFunc(3,2) # nulla viene ritornato}}} <<BR>> |
Line 74: | Line 64: |
<<BR>> | |
Line 75: | Line 66: |
<<BR>> | |
Line 77: | Line 69: |
Esiste una testsuite per il modulo. Come è usato il modulo rpc in Netsukuku |
Vedi anche [[../UsoDelModuloRPCInNetsukuku|come viene usato il modulo rpc in Netsukuku]]. |
Il modulo RPC
class RPCDispatcher(object)
Un'istanza della classe RPCDispatcher fornisce il metodo marshalled_dispatch(data) per richiamare le funzioni definite remotable sulla base di un blob (arrivato via rete) che codifica (tramite rencode - vedi il modulo rencode) nome-funzione e parametri.
Lato server è sufficiente che le funzioni abbiano il nome in remotable_funcs (in una classe di cui sono metodo)
MicroTCPServer(...)
La microfunc di modulo MicroTCPServer viene richiamata passando la cosidetta root_instance, cioè la classe con le remotable_funcs, che di norma è la stessa istanza di NtkNode che fa da collante tra i vari moduli (vedi la classe NtkNode).
Si istanzia un RPCDispatcher e poi sta in ascolto su un socket "stackless-wrapped" (vedi il modulo microsock per le operazioni di I/O in ambiente stackless), di default bindato alla porta 269 e non associato ad una specifica interfaccia di rete. Per ogni connessione che riceve richiama la microfunc micro_stream_request_handler e subito torna in ascolto.
Questa microfunc a) popola la classe CallerInfo con i dati del chiamante, b) legge dal socket il messaggio in un blob con _data_unpack_from_stream_socket, c) richiama la marshalled_dispatch del RPCDispatcher passando il blob e il CallerInfo, d) rinvia al socket la risposta ottenuta dal RPCDispatcher inpacchettandola con _data_pack.
MicroTCPServer è una microfunc, quindi si avvia in un microthread e resta sempre in vita. Viene però fornito un metodo stop_tcp_servers nel modulo RPC che permette di fermare il server.
class FakeRmt()
E' una classe che permette di chiamare una RPC con una sintassi identica alla chiamata di un metodo locale.
Ad esempio remote_instance.mymethod1.mymethod2.func(p1, p2, p3)
invece di remote_instance.rmt('mymethod1.method2.func', (p1, p2, p3))
In realtà il metodo rmt va implementato in una derivata di questa classe, con in esso la effettiva chiamata RPC.
class TCPClient(FakeRmt)
Semplice classe client che eredita da FakeRmt. Si usa tipo:
a = TCPClient('192.168.1.1',8888)
ret = a.rpc_call('nomefunc', (1,))
ret = a.nomefunc(1)
Alla chiamata di un metodo, si collega al MicroTCPServer remoto, invia in un blob il nome del metodo e gli argomenti, aspetta la risposta in un blob dal host remoto e la decodifica (la risposta può essere anche una eccezione). Poi il metodo termina restituendo la risposta al chiamante.
MicroUDPServer(...)
Le microfunc micro_dgram_request_handler e MicroUDPServer sono le analoghe di micro_stream_request_handler e MicroTCPServer in versione UDP broadcast.
Diversamente dalla MicroTCPServer, la MicroUDPServer viene richiamata n volte, una per ogni interfaccia di rete.
La MicroUDPServer viene richiamata passando la root_instance e l'interfaccia di rete. Si istanzia un RPCDispatcher e poi riceve i pacchetti (recvfrom(8192)) da un socket "stackless-wrapped" di tipo datagram, di default bindato alla porta 269 e associato alla specifica interfaccia di rete. Con ogni pacchetto che riceve richiama la microfunc micro_dgram_request_handler e subito torna in ascolto.
Questa microfunc a) popola la classe CallerInfo con i dati del chiamante, b) decodifica il pacchetto con _data_unpack_from_buffer, c) richiama la marshalled_dispatch del RPCDispatcher passando il blob e il CallerInfo.
MicroUDPServer è una microfunc, quindi ogni sua chiamata (una per interfaccia di rete) si avvia in un microthread e resta sempre in vita. Viene però fornito un metodo stop_udp_servers nel modulo RPC che permette di fermare tutti i servers udp avviati.
class BcastClient(FakeRmt)
Semplice classe client analoga di TCPClient in versione UDP broadcast.
La classe BcastClient si usa tipo:
a = BcastClient() # si può passare un elenco di interfacce
a.nomeFunc(3,2) # nulla viene ritornato
Alla chiamata di un metodo, si prepara un messaggio codificando in un blob il nome del metodo e gli argomenti.
Il messaggio è inviato in broadcast via tutte le interfacce di rete (o quelle richieste). Non si attende una risposta ma si fa subito ritorno al chiamante.
La versione broadcast (UDP) del rpc funziona solo per messaggi inferiori a 8 kB (when packed)
Vedi anche come viene usato il modulo rpc in Netsukuku.