I'm trying to use Pyro to control a slave machine. I rsync the necessary python files, start a Pyro server, perform some actions by remote control, and then I want to tell the Pyro server to shut down.
I'm having trouble getting the Pryo Daemon to shut down cleanly. It either hangs in the Daemon.close()
call, or if I comment out that line it exits without shutting down its socket correctly, resulting in socket.error: [Errno 98] Address already in use
if I restart the server too soon.
It don't think that SO_REUSEADDR is the right fix, as unclean socket shutdown still results in a socket hanging around in the TIME_WAIT state, potentially causing some clients to experience problems. I think the better solution is to convince the Pyro Daemon to close its socket properly.
Is it improper to call Daemon.shutdown() from within the daemon itself?
If I start a server and then press CTRL-C without any clients connected I don't have any problems (no Address already in use
errors). That makes a clean shutdown seem possible, most of the time (assuming an otherwise sane client and server).
Example: server.py
import Pyro4
class TestAPI:
def __init__(self, daemon):
self.daemon = daemon
def hello(self, msg):
print 'client said {}'.format(msg)
return 'hola'
def shutdown(self):
print 'shutting down...'
self.daemon.shutdown()
if __name__ == '__main__':
daemon = Pyro4.Daemon(port=9999)
tapi = TestAPI(daemon)
uri = daemon.register(tapi, objectId='TestAPI')
daemon.requestLoop()
print 'exited requestLoop'
daemon.close() # this hangs
print 'daemon closed'
Example: client.py
import Pyro4
if __name__ == '__main__':
uri = 'PYRO:TestAPI@localhost:9999'
remote = Pyro4.Proxy(uri)
response = remote.hello('hello')
print 'server said {}'.format(response)
try:
remote.shutdown()
except Pyro4.errors.ConnectionClosedError:
pass
print 'client exiting'
Serialization. Pyro will serialize the objects that you pass to the remote methods, so they can be sent across a network connection.
Pyro4 4.82 Pyro means PYthon Remote Objects. It is a library that enables you to build applications in which objects can talk to eachother over the network, with minimal programming effort.
I think this can be done without using timeout or loopCondition, by having your shutdown()
call the daemon's shutdown
. According to http://pythonhosted.org/Pyro4/servercode.html#cleaning-up:
Another possibility is calling Pyro4.core.Daemon.shutdown() on the running bdaemon object. This will also break out of the request loop and allows your code to neatly clean up after itself, and will also work on the threaded server type without any other requirements.
The following works on Python3.4.2 on Windows. The @Pyro4.oneway
decorator for shutdown
is not needed here, but it is in some situations.
server.py
import Pyro4
# using Python3.4.2
@Pyro4.expose
class TestAPI:
def __init__(self, daemon):
self.daemon = daemon
def hello(self, msg):
print('client said {}'.format(msg))
return 'hola'
@Pyro4.oneway # in case call returns much later than daemon.shutdown
def shutdown(self):
print('shutting down...')
self.daemon.shutdown()
if __name__ == '__main__':
daemon = Pyro4.Daemon(port=9999)
tapi = TestAPI(daemon)
uri = daemon.register(tapi, objectId='TestAPI')
daemon.requestLoop()
print('exited requestLoop')
daemon.close()
print('daemon closed')
client.py
import Pyro4
# using Python3.4.2
if __name__ == '__main__':
uri = 'PYRO:TestAPI@localhost:9999'
remote = Pyro4.Proxy(uri)
response = remote.hello('hello')
print('server said {}'.format(response))
remote.shutdown()
remote._pyroRelease()
print('client exiting')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With