import socket, cPickle def startServer(port,isDaemon=False): '''Run an RMI server on this host -- this function should be called before any object is exported from this host.''' global _SERVER_ADDRESS global _exportedObjects _SERVER_ADDRESS = socket.gethostname(), port _exportedObjects = dict() from threading import Thread class Server(Thread): def run(self): # set up server socket s = socket.socket() s.bind(_SERVER_ADDRESS) s.listen(1) while True: conn, _ = s.accept() dispatch(conn) server = Server() server.setDaemon(isDaemon) server.start() class RemoteObject(object): '''A tag class -- subclass this class to make objects that are always exported by reference rather than value.''' pass class _RemoteRef(object): '''Reference to an object on a foreign host.''' def __init__(self,serverAddress,remoteObjectId): self.serverAddress = serverAddress self.remoteObjectId = remoteObjectId def __repr__(self): return 'rmi._RemoteRef(%s,%s)' % (repr(self.serverAddress),repr(self.remoteObjectId)) __str__ = __repr__ def export(obj,objectID=None): '''Export obj with a given ID, or its object id.''' if objectID is None: objectID = id(obj) _exportedObjects[objectID] = obj def _translateObjectOut(obj): '''Translation of objects going out of the RMI server.''' if isinstance(obj,RemoteObject): export(obj) return _RemoteRef(_SERVER_ADDRESS,id(obj)) elif isinstance(obj,_ClientProxy): return _RemoteRef(obj._serverAddress,obj._remoteObjectId) else: return obj def _translateObjectIn(obj): '''Translation of objects coming from an RMI server.''' if isinstance(obj,_RemoteRef): return _ClientProxy(obj.serverAddress,obj.remoteObjectId) else: return obj class _RemoteMethod(object): '''A callable object that calls a remote method over a socket file.''' def __init__(self,name,serverAddress,remoteObjectId): self.name = name self.serverAddress = serverAddress self.remoteObjectId = remoteObjectId def __call__(self,*args,**kwargs): args = [_translateObjectOut(obj) for obj in args] kwargs = dict([(key,_translateObjectOut(obj)) for key,obj in kwargs.items()]) s = socket.socket() s.connect(self.serverAddress) f = s.makefile() cPickle.dump(self.remoteObjectId,f) cPickle.dump(self.name,f) cPickle.dump(args, f) cPickle.dump(kwargs, f) f.flush() res = cPickle.load(f) s.close() return _translateObjectIn(res) class _ClientProxy(object): '''Class functioning as the client-side proxy for a server-side object.''' def __init__(self,serverAddress,remoteObjectId): self._serverAddress = serverAddress self._remoteObjectId = remoteObjectId def __getattribute__(self,attr): if attr[0] != '_': # handle all non-special and non-private cases by proxy return _RemoteMethod(attr,self._serverAddress,self._remoteObjectId) else: # if it is a special or private, just use the # usual attribute access return object.__getattribute__(self, attr) def __repr__(self): return 'rmi._ClientProxy(%s,%s)' % (repr(self._serverAddress),repr(self._remoteObjectId)) __str__ = __repr__ def dispatch(conn): '''Handle dispatches of calls to exported objects at this server.''' connFile = conn.makefile() try: ID = cPickle.load(connFile) name = cPickle.load(connFile) args = cPickle.load(connFile) kwargs = cPickle.load(connFile) args = [_translateObjectIn(obj) for obj in args] kwargs = dict([(key,_translateObjectIn(obj)) for key,obj in kwargs.items()]) obj = _exportedObjects[ID] res = _translateObjectOut(getattr(obj,name)(*args,**kwargs)) cPickle.dump(res,connFile) ; connFile.flush() conn.close() except: pass