linux 下 rpc python 執行個體之使用XML-RPC進行遠程檔案分享權限設定

來源:互聯網
上載者:User

標籤:

  這是個不錯的練習,使用python開發P2P程式,或許通過這個我們可以自己搞出來一個P2P下載工具,類似於迅雷。XML-RPC是一個遠端程序呼叫(remote procedure call,RPC)的分散式運算協議,通過XML將調用函數封裝,並使用HTTP協議作為傳送機制[摘自維基百科]

 

1.先做一個小小的嘗試: 首先進入命令列,輸入vim pythonServer.py,然後輸入一下代碼: 

from simpleXMLRPCServerr import SimpleXMLRPCServerrs = SimpleXMLRPCServer(("",4242))  #預設為本機def twice(x):return x*xs.register_function(twice) #向伺服器添加功能s.serve_forever() #啟動伺服器

2. 輸入python,開啟shell 互動命令列

from xmlrpclib import ServerProxy s = ServerProxy(‘http://localhost:4242‘)s.twice(6) #通過ServerProxy調用遠端方法,

3.  開始檔案分享權限設定完整代碼:
3.1 伺服器端Server.py

#coding=utf-8from xmlrpclib import ServerProxy,Faultfrom os.path import join, abspath,isfilefrom SimpleXMLRPCServer import SimpleXMLRPCServerfrom urlparse import urlparseimport sysSimpleXMLRPCServer.allow_reuse_address = 1MAX_HISTORY_LENGTH = 6UNHANDLED = 100ACCESS_DENIED = 200class 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]            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)        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        name = join(dir, query)        if not isfile(name):raise UnhandledQuery        if not inside(dir,name):raise AccessDenied        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 UnhandledQuerydef main():    url, directory, secret = sys.argv[1:]    n = Node(url,directory,secret)    n._start()if __name__ == ‘__main__‘:     main()

  首先來看上面的幾個常量設定: SimpleXMLRPCServer.allow_reuse_address表示,其所佔用的連接埠可以重用,即如果你強制關閉node server之後再次重啟,不會出現連接埠被佔用的情況。

MAX_HISTORY_LENGTH = 6 這個是設定最大的節點長度,因為不能讓讓節點無休止的搜尋下去。

UNHANDLED = 100 ACCESS_DENIED = 200 這倆就是返回碼。

  然後再來看個node節點的具體流程。 這個段代碼的流程這這樣的,首先,啟動供遠程調用的伺服器,調用的介面就是Node類。在Node類中有三個方法供遠程調用的,一個是hello,一個是fetch還有一個query。hello 這個方法就是添加鄰節點資訊到當前節點中。而fetch則是用來擷取資料的方法,query是節點之間用來互動的。

在fetch方法中,首先判斷密碼是否正確,然後通過調用自己的query方法尋找資料。我們來看query方法,這個方法中,先是調用私人方法_handle本地尋找,如果沒找到,那麼在通過_broadcast介面在所有已知節點中發送廣播,這裡要注意histroy,每次廣播都會傳遞history這個參數,這個參數的作用有二:一是、防止往重複的節點中發送廣播;二是、限制當前所有連結節點的長度。

理解了一個node server的基礎功能之後,再來看對server進行管理的控制類代碼。

 

3.2 用戶端代碼 Client.py

#coding=utf-8from xmlrpclib import ServerProxy, Faultfrom cmd import Cmdfrom random import choicefrom string import lowercasefrom server import Node,UNHANDLED  #引入前面的serverfrom threading import Threadfrom time import sleepimport sysHEAD_START = 0.1SECRET_LENGTH = 100def 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)        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_exitdef main():    urlfile, directory, url = sys.argv[1:]    client = Client(url, directory, urlfile)    client.cmdloop()if __name__ == ‘__main__‘:    main()

  來分析一下這段代碼,前面的參數就不看了,很好理解,一開始有一個隨機產生密碼的函數,做什麼用的呢?主要是用來防止別人非法調用該控制所控制的node server的。這密碼 我們也不用記,因為我們有client的合法使用權。呵呵。

這段代碼的總體作用就是為你提供一個可視的命令列的介面,通過繼承cmd這個類,來解析你輸入的命令,比如程式運行之後,出現命令提示字元,你輸入fetch,那麼它會調用到do_fetch這個方法中來,並把參數傳遞進來。do_fetch這個方法的所用就是調用node server中的fetch方法,擷取資源。另外的一個do_exit很好理解,就是接受exit命令退出程式。

  在程式初始化的時候,還有一點需要注意,就是它會讀取你urlfile參數傳遞的檔案中的資料,這個裡面放的是節點的url地址。讀取之後程式會把這些地址加到相鄰節點中,供以後訪問。不過這個程式還有些不完善的地方就是在程式運行時,如果你修改了url配置的檔案,他不會讀取你新添加的節點url。不過這個修改很簡單,把擷取url的代碼放到do_fetch中就行了。

  在運行程式之前還有一些工作要做。 首先需要建立兩個檔案夾,A和C,C檔案夾裡面建立一個檔案,B.txt,在A和C所在檔案夾中建立urlsA.txt和urlsC.txt檔案。裡面在urlsA.txt中寫入:http://localhost:4243,然後開啟兩個命令列,

第一個輸入:

python client.py urlsA.txt A http://localhost:4242 

 斷行符號,是不是出來提示符了。輸入fetch B.txt斷行符號,看到提示Couldn‘t find the file B.txt。、

然後在第二個命令列中輸入

python client.py urlsC.txt C http://localhost:4243

 斷行符號。同樣輸入fetch B.txt斷行符號,是不是沒反應。說明該檔案存在。接在在第一個命令列中再次輸入fetch B.txt看,是否還是提示沒找到檔案,如果你對代碼根據我上面的建議進行了修改的話,就不會出現錯誤了,如果沒有修改,此時你需要把輸入exit退出程式,再次重啟,然後在fetch B.txt,然後到A檔案夾下查看一下,看是不是把B.txt下載到你的檔案夾中了。

  PS:上面的程式只能傳輸文字檔,大檔案或者其他格式的檔案無法傳輸,剛才研究了一下,使用xmlrpclib這個庫中的Binary函數即可,具體使用訪問為: 先引入xmlrpclib,import xmlrpclib 在server類的的_handle方法中最後返回的那句代碼return open(name).read() 修改為 return xmlrpclib.Binary(open(name,‘rb‘).read()) 再把fetch方法中的f.write(result)修改為f.write(result.data) 另外這句話前面的那個寫檔案的方式要改為wb。

 

【轉自】 python項目練習八:使用XML-RPC進行遠程檔案分享權限設定 感謝樓主!

參考:

 1 .python zeromq rpc介紹

 2. 聊聊Python用rpc實現分布式系統調用的那些事 

linux 下 rpc python 執行個體之使用XML-RPC進行遠程檔案分享權限設定

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.