用XML_RPC实现P2P,XML_RPC实现P2P,# -*- coding
# -*- coding: utf-8 -*-from xmlrpclib import ServerProxy, Faultfrom os.path import join, isfile, abspathfrom SimpleXMLRPCServer import SimpleXMLRPCServerfrom urlparse import urlparseimport sysimport xmlrpclibSimpleXMLRPCServer.allow_reuse_address = 1#避免循环请求和长链请求。之所以用6是采用了六度分隔的原理MAX_HISTORY_LENGTH = 6UNHANDLED = 100ACCESS_DENIED = 200class UnhandledQuery(Fault): def __init__(self, message="Counldn't handle the query"): Fault.__init__(self, UNHANDLED, message)class AccessDenied(Fault): def __init__(self, message='Access denied'): Fault.__init__(self, ACCESS_DENIED, message)def inside(dirs, name): the_dir = abspath(dirs) name = abspath(name) return name.startswith(join(the_dir, ''))def getPort(url): name = urlparse(url)[1] parts = name.split(':') return int(parts[-1])class Node: def __init__(self, url, dirname, secret): self.url = url self.dirname = dirname self.secret = secret self.known = set() def query(self, query, history=[]): try: return self._handle(query) except UnhandledQuery: history = history + [self.url] if len(history) >= MAX_HISTORY_LENGTH: raise return self._broadcast(query, history) def hello(self, other): self.known.add(other) return 0 def fetch(self, query, secret): """找到并下载资源""" if secret != self.secret: raise AccessDenied result = self.query(query) f = open(join(self.dirname, query), 'wb') f.write(result.data) f.close() return 0 def _start(self): #启动XML_RPC服务器 s = SimpleXMLRPCServer(("", getPort(self.url)), logRequests=False) s.register_instance(self) s.serve_forever() def _handle(self, query): """处理请求""" name = join(self.dirname, query) if not isfile(name): raise UnhandledQuery if not inside(self.dirname, name): raise AccessDenied return xmlrpclib.Binary(open(name, 'rb').read()) def _broadcast(self, query, history): """将查询广播到所有已知的Node""" for other in self.known.copy(): if other in history: continue try: s = ServerProxy(other) return s.query(query, history) except Fault, f: if f.faultCode == UNHANDLED: pass else: self.known.remove(other) except: self.known.remove(other) raise UnhandledQuerydef main(): url, directory, secret = sys.argv[1:] n = Node(url, directory, secret) n._start()if __name__ == '__main__': try: main() except KeyboardInterrupt: sys.exit()
评论关闭