XMLRPC远程共享

 XML-RPC的全称是XML Remote Procedure Call,即XML远程方法调用。

 它是一套允许运行在不同操作系统、不同环境的程序实现基于Internet过程调用的规范一系列的实现

这种远程过程调用使用http作为传输协议XML作为传送信息的编码格式Xml-Rpc的定义尽可能的保持了简单,但同时能够传送、处理、返回复杂的数据结构。

XML-RPC是工作在Internet上的远程过程调用协议。一个XML-RPC消息就是一个请求体为xmlhttp-post请求被调用的方法在服务器端执行并将执行结果以xml格式编码后返回。


共享文件,我们经常在用,只不过是用鼠标点点而已,用代码共享还真不知道,而且还可以远程共享,当然得知道对方的IP和端口,做这个项目刚开始还真看不懂,因为好多模块及其的方法都不晓得。其中加 了些print ,因为不知道他输出的和我想的一样不。里面还涉及一点线程的知识,不过我还是不懂。


和以前一样,这个也需要一个服务器和一个客户端,总的来讲就是先在一个目录下获取一个不存在的文件(当然获取不到),然后在另一个目录中获取一个存在的文件,系统会把存在的那个文件的url 保存到history列表中,再从第一个目录中获取同一个文件的时候就可以下载到本目录了。


先看代码server.py


from xmlrpclib import ServerProxy,Fault
from os.path import join, abspath,isfile
from SimpleXMLRPCServer import SimpleXMLRPCServer
from urlparse import urlparse
import sys

SimpleXMLRPCServer.allow_reuse_address = 1

MAX_HISTORY_LENGTH = 6

UNHANDLED = 100
ACCESS_DENIED = 200

class UnhandledQuery(Fault):
    '''
    that's show can't handle the query exception
    '''
    def __init__(self,message="Couldn't handle the query"):
        Fault.__init__(self, UNHANDLED, message)

class AccessDenied(Fault):
    '''
    when user try to access the forbiden resources raise exception
    '''
    def __init__(self, message="Access denied"):
        Fault.__init__(self, ACCESS_DENIED, message)

def inside(dir,name):
    '''
    check the dir that user defined is contain the filename the user given
    '''
    dir = abspath(dir)
    name = abspath(name)
    return name.startswith(join(dir,''))
def getPort(url):
    '''
    get the port num from the 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]
            print history
            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
        result = self.query(query)
        print query
        f = open(join(self.dirname, query),'w')
        f.write(result)
        f.close()
        return 0

    def _start(self):
        s = SimpleXMLRPCServer(("",getPort(self.url)),logRequests=False)
        s.register_instance(self)
        s.serve_forever()

    def _handle(self, query):
        dir = self.dirname
        print dir
        name = join(dir, query)
        if not isfile(name):raise UnhandledQuery
        if not inside(dir,name):raise AccessDenied
        print name
        return open(name).read()

    def _broadcast(self, query, history):

        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 UnhandledQuery

def main():
    url, directory, secret = sys.argv[1:]
    print url
    print directory
    print secret
    n = Node(url,directory,secret)
    n._start()

if __name__ == '__main__': main()

接着是客户端,client.py  ,因为客户端要连接服务器,所以一起说了:
from xmlrpclib import ServerProxy, Fault
from cmd import Cmd
from random import choice
from string import lowercase
from server import Node,UNHANDLED 
from threading import Thread
from time import sleep

import sys

HEAD_START = 0.1
SECRET_LENGTH = 100

def randomString(length):
    chars = []
    letters = lowercase[:26]
    while length > 0:
        length -= 1
        chars.append(choice(letters))
    return ''.join(chars)

class Client(Cmd):
    prompt = '> '

    def __init__(self, url, dirname, urlfile):

        Cmd.__init__(self)
        self.secret = randomString(SECRET_LENGTH)
        print '%s' %(self.secret)
        n = Node(url, dirname, self.secret)
        t = Thread(target = n._start)
        t.setDaemon(1)
        t.start()

        sleep(HEAD_START)
        self.server = ServerProxy(url)
        for line in open(urlfile):
            line = line.strip()
            self.server.hello(line)

    def do_fetch(self, arg):
        try:
            self.server.fetch(arg,self.secret)
        except Fault,f:
            if f.faultCode != UNHANDLED: raise
            print "Couldn't find the file",arg

    def do_exit(self,arg):
        print
        sys.exit()

    do_EOR = do_exit

def main():
    urlfile, directory, url = sys.argv[1:]
    print  urlfile, directory, url
    client = Client(url, directory, urlfile)
    client.cmdloop()

if __name__ == '__main__':
    main()

先从client的main开始说吧,说到开始就必须说下sys.argv这个方法,因为你要运行这个程序,不能直接从解释器直接运行,需要进入DOS之类的终端输入python client.py url.txt file1 http://localhost:4242 (环境变量一定要配置好),sys,argv是个列表,存储的就是你输入的命令行参数,也就是python之后的所有代码,其中client.py存在sys.argv[0]中,是我们不需要的,所以刚开始的代码中指定了sys.argv[1:],获取了文件名,目录和url,然后就定义了类Client的对象,并且把文件名,目录,url做参数,其中类Client也是继承了父类Cmd,说到Cmd类,他主要是实现命令的方法,比如这个项目就两个供我们使用的命令,fetch和exit,使用这两个命令的时候就分别调用了内部的do_fetch()和do_exit()方法,用于获取信息和退出系统,而fetch后面的其他部分会作为参数传递给do_fetch()。‘>’ 就是运行client之后的提示,刚开始就用构造方法分别初始化了Client和Cmd类,接着是randomSting方法,他的主要意思是随机生成100个小写字母的组合,称之为密码吧。然后创建server服务器代码中的Node类的对象,自动初始化实例的特性,然后就是利用一个单线程,在独立的线程中调用_start方法,_start方法创建了一个SimpleXMLRPCServer对象,参数中使用了一个来获取端口的函数getPort(),之后用register_instance注册self,调用服务器端的serve_forever方法,t.start()是线程开始运行吗?我也不知道,为了确保服务器能在使用XMLRPC进行连接前启动,应该先启动服务器,然后使用 time.sleep()延时一会,ServerProxy方法就是连接服务器了,之后再url文件中遍历所有行,调用hello方法,把每行的内容存储到一个集合中。

当使用fetch命令的时候,调用do_fetch方法,在try中调用服务器端的fetch方法,首先判断下密码,然后,调用实例的query方法,这个主要是查询的意思,看看这个文件存不存在,内部会调用_handle方法,_handle方法会引发两个异常(UnahndledQuery,AccessDenied)这些异常是xmlrpclib.Fault的子类,当他们在服务器端被引发的时候,会被传递到拥有相同faultCode的客户端里,最后会把url文件里的内容写入获取他的那个目录里。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值