RPC,RPC(Remote Procedure Call)是指遠程過程調用,它是一種通過網路從遠程電腦程式上請求服務,而不需要瞭解底層網路技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,為通信程式之間攜帶資訊數據。在OSI網路通信模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網路分佈式多程式在內的應用程式更加容易。
RPC採用客戶機/伺服器模式。請求程式就是一個客戶機,而服務提供程式就是一個伺服器。首先,客戶機調用進程發送一個有進程參數的調用資訊到服務進程,然後等待應答資訊。在伺服器端,進程保持睡眠狀態直到調用資訊到達為止。當一個調用資訊到達,伺服器獲得進程參數,計算結果,發送答復資訊,然後等待下一個調用資訊,最後,客戶端調用進程接收答復資訊,獲得進程結果,然後調用執行繼續進行。
它是一種遠程調用函數介面的方式,客戶端和服務端之間約定一種契約(函數介面),然後服務端一直等待客戶端的調用。有點像平常的WEB網路請求,不過這種方式非常輕量,不涉及HTTP這些東西,待會可以看到實現很簡單。
上面說了,一種用途是在多臺伺服器之間互相進行調用,另一個用途則在於,不同編程語言之間都支持這種方式,像Python更是內置對其的支持,不需要額外安裝什麼庫,所以可以直接在多語言的伺服器之間互相進行調用,很簡單。
xmlrpc庫
在Python2中,服務端需要用到SimpleXMLRPCServer庫,客戶端需要用到ServerProxy庫,而在Python3中,兩者被整合到了同一個xmlrpc庫中,分為xmlrpc.server和xmlrpc.client兩部分。所以如果在Python3下使用,就需要導入這個庫了。
1. 簡單的伺服器端
伺服器端像web請求一樣,需要確定供客戶端訪問的url和端口號,以及供客戶端調用的方法實現,最後要讓我們伺服器一直處於等待被訪問的狀態,下麵伺服器簡單實現返回當前時間,原始檔案:server.py -
import datetime
from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client
def today():
today = datetime.datetime.today()
return xmlrpc.client.DateTime(today)
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(today, "today")
server.serve_forever()
創建客戶端,調用伺服器端過程得到當前時間。原始檔案:client.py -
import xmlrpc.client
import datetime
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
today = proxy.today()
# convert the ISO8601 string to a datetime object
converted = datetime.datetime.strptime(today.value, "%Y%m%dT%H:%M:%S")
print("Today: %s" % converted.strftime("%d.%m.%Y, %H:%M"))
首先運行 server.py,然後再運行client.py,得到以下結果 -
示例2
二進位對象的示例用法。在下面這個示例中,要通過XMLRPC傳輸圖片:
原始檔案:server.py -
from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client
def python_logo():
with open("python_logo.jpg", "rb") as handle:
return xmlrpc.client.Binary(handle.read())
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(python_logo, 'python_logo')
server.serve_forever()
原始檔案:client.py -
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
with open("/home/zaixian/zaixian-logo.jpg", "wb") as handle:
handle.write(proxy.python_logo().data)
示例3
MultiCall對象提供了一種將對遠程伺服器的多個調用封裝到單個請求中的方法。下麵是該類的用法示例。
伺服器原始檔案:server.py -
from xmlrpc.server import SimpleXMLRPCServer
def add(x, y):
return x + y
def subtract(x, y):
return x - y
def multiply(x, y):
return x * y
def divide(x, y):
return x // y
# A simple server with simple arithmetic functions
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_multicall_functions()
server.register_function(add, 'add')
server.register_function(subtract, 'subtract')
server.register_function(multiply, 'multiply')
server.register_function(divide, 'divide')
server.serve_forever()
客戶端原始檔案:client.py -
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
multicall = xmlrpc.client.MultiCall(proxy)
multicall.add(7, 3)
multicall.subtract(7, 3)
multicall.multiply(7, 3)
multicall.divide(7, 3)
result = multicall()
print("7+3=%d, 7-3=%d, 7*3=%d, 7//3=%d" % tuple(result))