Anonymous user
Distributed programming: Difference between revisions
→Socket, Plain Text: changed the code to make it satisfy the task description
Capra Hircus (talk | contribs) No edit summary |
(→Socket, Plain Text: changed the code to make it satisfy the task description) |
||
Line 974:
print 'Server Message: %s' % response.read()</lang>
===Socket,
'''Protocol:''' raw socket / pickle format
This example builds a very basic RPC mechanism on top of sockets and the [http://docs.python.org/library/pickle.html#module-pickle pickle module]. Please note that the pickle module is not secure - a malicious client can build malformed data to execute arbitrary code on the server. If untrusted clients can access the server, the [http://docs.python.org/library/json.html json module] could be used as a substitute, but we lose the ability to transfer arbitrary Python objects that way.
==== Server ====
<lang python>#!/usr/bin/python
# -*- coding: utf-8 -*-
import SocketServer
import pickle
HOST = "localhost"
PORT = 8000
class RPCServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
# The object_to_proxy member should be set to the object we want
# methods called on. Unfortunately, we can't do this in the constructor
# because the constructor should not be overridden in TCPServer...
daemon_threads = True
class RPCHandler(SocketServer.StreamRequestHandler):
def handle(self):
in_channel = pickle.Unpickler(self.rfile)
out_channel = pickle.Pickler(self.wfile, protocol=2)
name, args, kwargs = in_channel.load()
print 'got %s %s %s' % (name, args, kwargs)
except EOFError:
# EOF means we're done with this request.
# Catching this exception to detect EOF is a bit hackish,
# but will work for a quick demo like this
break
try:
method = getattr(self.server.object_to_proxy, name)
result = method(*args, **kwargs)
except Exception, e:
out_channel.dump(('Error',e))
else:
out_channel.dump(('OK',result))
class MyHandlerInstance(object):
def echo(self, data):
'''Method for returning data got from client'''
return 'Server responded: %s' % data
def div(self, dividend, divisor):
'''Method to divide 2 numbers'''
return dividend/divisor
def is_computer_on(self):
return True
if __name__ == '__main__':
rpcserver.object_to_proxy = MyHandlerInstance()
try:
except KeyboardInterrupt:
print 'Exiting...'
</lang>
==== Client ====
<lang python>#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket
import pickle
HOST = "localhost"
PORT = 8000
class RPCClient(object):
def __init__(self, host, port):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((host, port))
self.rfile = self.socket.makefile('rb')
self.wfile = self.socket.makefile('wb')
self.in_channel = pickle.Unpickler(self.rfile)
self.out_channel = pickle.Pickler(self.wfile, protocol=2)
def _close(self):
self.socket.close()
self.rfile.close()
self.wfile.close()
# Make calling remote methods easy by overriding attribute access.
# Accessing any attribute on our instances will give a proxy method that
# calls the method with the same name on the remote machine.
def __getattr__(self, name):
def proxy(*args, **kwargs):
self.out_channel.dump((name, args, kwargs))
self.wfile.flush() # to make sure the server won't wait forever
status, result = self.in_channel.load()
if status == 'OK':
return result
else:
raise result
return proxy
if __name__ == '__main__':
# connect to server and send data
rpcclient = RPCClient(HOST, PORT)
print 'Testing the echo() method:'
print rpcclient.echo('Hello world!')
print
print 'Calculating 42/2 on the remote machine:'
print rpcclient.div(42, 2)
print
print 'is_computer_on on the remote machine returns:'
print rpcclient.is_computer_on()
print
print 'Testing keyword args:'
print '42/2 is:', rpcclient.div(divisor=2, dividend=42)
rpcclient._close()
del rpcclient</lang>
===Pyro===
|