一、RPC簡介
1. RPC
RPC (Remote Procedure Call) 即遠程過程調用,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。RPC在通信中可以爲通信程序之間攜帶信息數據。在OSI網絡通信模型中,RPC跨越了傳輸層和應用層,是分佈式系統中常見的一種通信方法。
RPC採用客戶端/服務器模式。請求程序就是一個客戶端,而提供服務的程序就是一個服務器。首先,客戶端調用進程發送一個請求信息到服務器端,然後等待應答信息。在服務器端,進程保持睡眠狀態直到請求信息到達爲止。當一個請求信息到達,服務器獲得進程參數,然後執行對應的服務方法並返回結果給客戶端,隨後繼續等待下一個請求信息,直到關閉服務器端進程爲止。
2. xmlrpc庫
在Python2中服務器端需要用到SimpleXMLRPCServer
庫,客戶端需要用到ServerProxy
庫,而在Python3中,兩者被整合到了同一個xmlrpc
庫中,分別是xmlrpc.server
和xmlrpc.client
。
二、簡單使用
1. 服務器端的實現
因爲是從網絡訪問,所以和web請求一樣,我們需要確定供客戶端訪問的URL
和端口號
,以及供客戶端調用的服務方法
,最後還要讓我們的服務器一直處於可以被訪問的狀態
。
Example:
from xmlrpc.server import SimpleXMLRPCServer
__author__ = 'Evan'
def setup_socket_server(ip_address='localhost', port=6666):
"""
註冊一個函數或者類來響應XML-RPC請求,並啓動XML-RPC服務器
:param ip_address: 供客戶端連接的IP地址,默認使用localhost,localhost爲當前網卡IP,也可以自己指定合法有效的IP地址
:param port: 供客戶端連接的端口號,默認爲6666
:return:
"""
try:
service = SimpleXMLRPCServer((ip_address, port)) # 初始化XML-RPC服務
# 註冊一個函數來響應XML-RPC請求,客戶端只能調用已註冊的函數,比較單一
service.register_function(function)
# 註冊一個類來響應XML-RPC請求,使用類的好處就是可以把多個方法寫到一起,方便管理和調用
service.register_instance(ServiceMethod())
service.serve_forever() # 啓動服務器並永久運行
except Exception as ex:
raise Exception('Setup socket server error:\n{}'.format(ex))
上面這段代碼描述了一個簡單的服務器端實現過程,下面開始展示完整的服務器端配置過程
代碼如下:
# -*- coding:utf-8 -*-
import os
import re
from xmlrpc.server import SimpleXMLRPCServer
__author__ = 'Evan'
class ServiceMethod(object):
"""
這個類包含客戶端所有能被執行的方法
每個方法必須要有一個返回值,如果沒有合適的返回值可以直接返回True
"""
@staticmethod
def get_server_ip():
"""
獲取服務器端的IP地址
:return:
"""
result = os.popen('ipconfig')
ip_address = re.search(r'IPv4.+?: (\d+?\.\d+?\.\d+?\.\d+)', result .read())
if ip_address:
return ip_address.group(1)
else:
return 'Server ip address was not found'
def get_server_host_name():
"""
這是獲取服務器端計算機主機名的函數
:return:
"""
result = os.popen('ipconfig /all')
host_name = re.search(r'主機名.+?: (\w+)', result.read())
if host_name:
return host_name.group(1)
else:
return 'Server host name was not found'
def setup_socket_server(ip_address='localhost', port=6666):
"""
註冊一個函數或者類來響應XML-RPC請求,並啓動XML-RPC服務器
:param ip_address: 供客戶端連接的IP地址,默認使用localhost,localhost爲當前網卡IP,也可以自己指定合法有效的IP地址
:param port: 供客戶端連接的端口號,默認爲6666
:return:
"""
try:
service = SimpleXMLRPCServer((ip_address, port)) # 初始化XML-RPC服務
print('Server {} Listening on port {} ...'.format(ip_address, port))
service.register_function(get_server_host_name) # 註冊一個函數
service.register_instance(ServiceMethod()) # 註冊一個類
service.serve_forever() # 啓動服務器並永久運行
except Exception as ex:
raise Exception('Setup socket server error:\n{}'.format(ex))
if __name__ == '__main__':
setup_socket_server(ip_address='172.31.9.156')
執行結果:
Server 172.31.9.156 Listening on port 6666 ...
我這裏用的是本機自動分配的IP地址,像這樣一個服務器端就啓動好了,這個Python進程在執行後就不會關閉了,這裏有註冊兩個可調用的方法get_server_host_name
,ServiceMethod()
,接下來看客戶端的實現。
2. 客戶端的實現
客戶端需要配置服務器端的IP地址
和端口號
初始化一個服務器對象,然後調用對應的服務器端方法即可。
代碼如下:
# -*- coding:utf-8 -*-
from xmlrpc.client import ServerProxy
__author__ = 'Evan'
def setup_socket_client(ip_address, port=6666):
proxy = ServerProxy('http://%s:%s/' % (ip_address, port), allow_none=True)
print('Connect to {}:{} successful ...'.format(ip_address, port))
host_name = proxy.get_server_host_name()
print('Received the server host name: {}'.format(host_name))
server_ip = proxy.get_server_ip()
print('Received the server ip: {}'.format(server_ip))
if __name__ == '__main__':
setup_socket_client(ip_address='172.31.9.156')
客戶端執行結果:
Connect to 172.31.9.156:6666 successful ...
Received the server host name: EVALIU
Received the server ip: 172.31.9.156
連接服務器端成功,並打印了服務器端函數的返回結果
下面看服務器端響應結果:
Server 172.31.9.156 Listening on port 6666 ...
172.31.9.156 - - [15/Jan/2020 10:05:10] "POST / HTTP/1.1" 200 -
172.31.9.156 - - [15/Jan/2020 10:05:10] "POST / HTTP/1.1" 200 -
可以看到,服務器每次被訪問都會打印出訪問來源,我這裏是本機客戶端連接本機服務器端所以IP地址都是一樣的。