RPyC 3.0.7: Decoupled services

147 views
Skip to first unread message

Amy Allen

unread,
Sep 22, 2010, 9:25:15 AM9/22/10
to rpyc
I am trying to use RPyC 3.0.7's services interface, and can't figure
out how do I reach the Client's method of the server side.

I know how to set up a service in both the rpyc server and client, and
know how to use the server's methods on the client's side, (I use the
rpyc connection object's root attribute) but can't find any such
object in the server I set up.

Could you point me to some helpful tutorial, demonstrating the use of
decoupled services?

tomer filiba

unread,
Sep 22, 2010, 10:30:59 AM9/22/10
to rp...@googlegroups.com, Amy Allen
hi amy

the rpyc protocol is symmetrical, meaning it works the same on both ends. however, the two ends may provide different services. by default, when a client connects to a server, the client exposes the VoidService, which, as the name suggests, does nothing. if you provide a custom service class, it will be exposed by the client.

have a look at this example:

>>> import rpyc
>>>
>>> class ServerService(rpyc.Service):
...     def exposed_foo(self, x):
...         self._conn.root.bar(x * 2)  # call the other end's bar()
...
>>> class ClientService(rpyc.Service):
...     def exposed_bar(self, y):
...         print "i got", y
...
>>> c = rpyc.connect_thread(service = ClientService, remote_service = ServerService)
>>> c.root.foo(17) # this will invoke foo() on the server, which will invoke bar() on the client
i got 34
>>>

so connect_thread is a may be considered "cheating", but it's only because i didn't have time to write a full-blown server-client pair.

on the typical topology, your server will look like:
if __name__ == "__main__":
    ThreadedServer(ServerService).start()

and the client would look like:
c = rpyc.connect("hostname", 12345, service = ClientService)
c.foo(17)

connect_thread simply combines the two into a single process -- creating a thread for the server, exposing remote_service, while the client exposes its own service.

i hope this will get you going :)
-tomer


An NCO and a Gentleman

Роман Бородин

unread,
Sep 23, 2010, 3:05:22 AM9/23/10
to rp...@googlegroups.com
Hi, Amy.
From server service client exposed service available in "self._conn.root".
My example:

class ServerService(rpyc.Service):
def on_connect(self):
self.client_service = self._conn.root
def on_disconnect(self):
pass
...

When a client connection established variable "client_service" of
ServerService instanse get reference of client exposed service.

22.09.2010 17:25, Amy Allen пишет:

Amy Allen

unread,
Sep 23, 2010, 9:14:26 AM9/23/10
to rpyc
I'm afraid I don't understand your example.

Assuming the first example is the server side's code, it appears like
the server has to have a client service in its scope, and performs its
methods locally.

I wish for my server's code to call for the remote client's method's.
(Whose implementation is unknown to me)

Besides, I don't understand what local and remote services mean. I
used to believe that each side (Client or server) exposes a single
service to be used by the other side. (The client exposes some
ClientService to be used by the Server, and the Server exposes a
ServerService for the Client to use)

Assume that the client exposes a method called "ClientMethod", and the
server one called "ServerMethod", (On Client and Server services
respectively) please describe the main program in each server, if the
server wishes to execute the ClientMethod, and the client
ServerMethod.
> > decoupled services?-הסתר טקסט מצוטט-
>
> -הראה טקסט מצוטט-

Amy Allen

unread,
Sep 23, 2010, 9:24:06 AM9/23/10
to rpyc
Joining both your and Filiba's answer, I think I might have
understood:
You suggest that I use the ServerService's instance's _conn (Which
is the rpyc connection to the client), to use the Client's exposes
service?

And by connecting the server to itself, I will gain access to its
ServerService instance and through it gain access to the rpyc
connection to the client?

And to use it, I'll need to have both side's methods declared in my
service? (My actual services for the client to use, and bogus services
for me to use)


Kinds of seems like it'll do that job, but is pretty ugly in my
opinion. If setting up the Server thread would have somehow exposed
the connection to its client, It'd make a lot more sense



Is that really what you suggested?

Роман Бородин

unread,
Sep 23, 2010, 9:42:45 AM9/23/10
to rp...@googlegroups.com
Hi Amy.

Here is examples of client.py and server.py

----------------begin client.py---------------------
import rpyc

class ClientService(rpyc.Service):
def on_connect(self):
self.server_service = self._conn.root # get server exposed
service inside client service
self.server_service.server_method() # prints "It's server
method" on server's stdout
def exposed_client_method(self):
print "It's client method!!!"

connection = rpyc.connect('localhost', 18861, service=ClientService)
server_service = connection.root # get server exposed service outside
client service
server_service.server_method() # prints "It's server method" on server's
stdout
----------------end client.py------------------------

----------------begin server.py--------------------

import rpyc
from rpyc.utils.server import ThreadedServer

class ServerService(rpyc.Service):
def on_connect(self):
self.client_service = self._conn.root

self.client_service.client_method() # prints "It's client
method" on client's stdout
def exposed_server_method(self):
print "It's server method!!!"
server = ThreadedServer(ServerService)
server.start()
-------------------end server.py---------------------


23.09.2010 17:14, Amy Allen пишет:

tomer filiba

unread,
Sep 23, 2010, 3:11:20 PM9/23/10
to rp...@googlegroups.com
roman, thanks for your elaborate code.

just one thing though -- it is better not to use code that calls the client in on_connect(), because if both sides do that, it *might* lead to recursive initialization of both ends, and is likely to cause a deadlock.

this isn't necessarily bound to happen, but i've seen happening and it's good to keep that in mind. for one thing -- that's why the Connection's ctor takes an extra parameter, _lazy, which can be used to delay calling of on_connect.


An NCO and a Gentleman


Amy Allen

unread,
Sep 24, 2010, 7:02:22 PM9/24/10
to rpyc
to Роман Бородин:
But you did here the same thing.
I would like you to be able to call 'client_method' in the server's
main scope, not inside one of its services.

I would like to start the server thread, and be able to call the
clients methods *whenever I wish*. (No just on connection)

On the client's side it is easy, because the function "Connect"
returns a connection object which allows me access to the Server's
service's methods. How can I do this in the server's side?
> >> -הראה טקסט מצוטט--הסתר טקסט מצוטט-
>
> -הראה טקסט מצוטט-

Amy Allen

unread,
Sep 25, 2010, 10:21:09 AM9/25/10
to rpyc
In short - I would like that, after starting the Server's thread, I
will have some connection object 'conn', which will have a root
attribute, through which I will be able to call the Client's methods.

Роман Бородин

unread,
Sep 27, 2010, 6:19:51 AM9/27/10
to rp...@googlegroups.com
Every time client connect to the server server's service starts in new
thread.
To get clients service from main scope (main thread) you need connect
every new thread with main thread (maybe over pipe or something else).
I did not do that before.
25.09.2010 03:02, Amy Allen пишет:

Amy Allen

unread,
Sep 28, 2010, 11:12:51 AM9/28/10
to rpyc
So how is the server expected to use the client's service?
Only in its own service? (Meaning that it can only be triggered by the
client)

Doesn't sound too symmetrical to me.

Amy Allen

unread,
Oct 12, 2010, 7:36:18 PM10/12/10
to rpyc
Should I take the silence as consent?

Is there no way to access the client's service outside the server's
service?
Reply all
Reply to author
Forward
0 new messages