用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()

评论关闭