標籤:

Python 遠程訪問系列之分散式RPC(上)

本系列將討論使用Python通過網路進行遠程訪問。

==================================================================================================================================================================================================================

1.RPC和rpyc

提到遠程訪問,大家可能第一印象是使用瀏覽器訪問互聯網上的網頁內容。但本篇打算討論一些更為基礎的技術。

RPC(Remote Procedure Call)的意思是,運行在一個環境下的程序去調用另外一個環境中的代碼,看起來就如同是調用自己的代碼一樣。這裡所說的「環境」取決於具體實現的場合。狹義的說,不同的環境指的是網路上不同的機器。RPC強調的是,程序員無需了解網路通訊的各種細節,透明的調用各種函數服務。而這些網路通訊、數據轉換的工作就交給了RPC的實現。RPC最普遍的應用是遠程控制以及分散式計算。

RPC不是一個有嚴格定義的協議,所以通常稱為RPC機制。RPC機制下通常會定義服務端和客戶端。發起代碼調用的一端叫做客戶端,實際執行代碼的一端叫做服務端。

rpyc就是在Python中實現了RPC。使用rpyc,一個Python程序可以透明的調用另外一個Python程序中的函數。

rpyc使用pip安裝:

pip install -U rpycn

rpyc有兩種截然不同的使用模式,下面分別討論。

2. rpyc的經典模式

rpyc的經典模式和木馬非常的像。經典模式下,服務端暴露自己所有的資源給客戶端。通常,你不需要自己寫服務端代碼,rpyc帶了一個小腳本,在服務端運行起來就可以。這個腳本名字叫rpyc_classic.py,在Windows下,它位於安裝目錄的Scripts子目錄下;在Linux/macOS下,它會被放在/usr/bin里

不帶任何參數啟動這個腳本,當前的Python環境就變成了服務端。在輸出信息里我們可以看到默認埠為18812。這個設置可以修改,具體可以用參數-h啟動該腳本查看所有的配置方法。

INFO:SLAVE/18812:server started on [0.0.0.0]:18812n

使用該方法,客戶端可以使用服務端所有的Python庫,以及服務端Python能夠訪問到的所有資源。下面舉幾個例子:

使用服務端的numpy進行計算

這個例子很有代表意義,例如可在一台高性能的電腦上部署rpyc的服務端,在一台性能很低的電腦(例如樹莓派)上借用服務端的資源進行數學計算。

這個例子是把一個正弦信號做快速傅立葉變換。首先我們看本地的版本:

import matplotlib.pyplot as pltnimport numpy as npnt = np.arange(256)nsp = np.fft.fft(np.sin(t))nfreq = np.fft.fftfreq(t.shape[-1])nplt.plot(freq.tolist(), sp.real.tolist(), freq.tolist(), sp.imag.tolist())nplt.show()n

得到這樣一張圖:

如何把它改成RPC機制,使得正弦運算、快速傅立葉運算能夠在高性能的遠程伺服器上運行呢?非常簡單,只需要處理import numpy as np一句即可。新的代碼:

import matplotlib.pyplot as pltnimport rpycnconn = rpyc.classic.connect("SUPER-HOST") #change SUPER-HOST to your own server ipnnp = conn.modules.numpyn#import numpy as npnt = np.arange(256)nsp = np.fft.fft(np.sin(t))nfreq = np.fft.fftfreq(t.shape[-1])nplt.plot(freq.tolist(), sp.real.tolist(), freq.tolist(), sp.imag.tolist())nplt.show()n

之後的代碼無需任何修改。注意pyplot仍然使用客戶端本地的庫,這樣圖像仍然在本地顯示出來。

訪問遠程資源

對於文件資源,可以利用服務端的內建函數進行訪問。舉例如下:

import rpycnconn = rpyc.classic.connect("HOSTNAME")nfopen = conn.builtin.opennfp = fopen("test.txt",mode=w)nfp.write("hello")nfp.close()n

test.txt將出現在服務端你運行服務端腳本的目錄下。

rpyc也準備了rpyc.classic.upload、rpyc.classic.download方法,供顯式文件或者目錄的傳輸,其實現方法也是對conn.buildin.open的包裝。

對於其他類型的資源以此類推,分清楚什麼東西在客戶端,什麼東西在服務端即可。比如下面的程序能夠播放來自服務端的音樂。那麼,音樂數據應該使用服務端,而播放器應該使用客戶端。

import pyaudionimport rpycnconn = rpyc.classic.connect("HOSTNAME")nwave = conn.modules.wavennchunk = 1024nwf = wave.open(1.wav, rb) # file 1.wav is at servernp = pyaudio.PyAudio()nnstream = p.open(n format = p.get_format_from_width(wf.getsampwidth()),n channels = wf.getnchannels(),n rate = wf.getframerate(),n output = True)ndata = wf.readframes(chunk)nnwhile data != :n stream.write(data)n data = wf.readframes(chunk)nnstream.close()np.terminate()n

遠程交互

本例展示了業務邏輯代碼在客戶端,而顯示工作在服務端的情況。服務端需要安裝PyQt4,然後把下面的代碼創建為qt.py並放在Python的庫目錄中:

from PyQt4.QtCore import *nfrom PyQt4.QtGui import *nimport sysnndef app():n return QApplication(sys.argv)n

無需重啟服務端腳本。在客戶端運行下面的代碼

import rpycnconn = rpyc.classic.connect("127.0.0.1")nqt = conn.modules.qtnnapp = qt.app()nline_edit = qt.QLineEdit()nline_edit.show()napp.exec_()nprint line_edit.text()n

服務端即出現了文本框,在文本框輸入任意字元,關閉文本框後,客戶端會得到這些字元。

rpyc的經典模式就討論到這裡,下一節我們討論rpyc的服務模式。


推薦閱讀:

TAG:Python |