11.6 通过XML-RPC实现简�的远程调用¶
问题¶
ä½ æƒ³æ‰¾åˆ°ä¸€ä¸ªç®€å�•的方å¼�去执行è¿�行在远程机器上é�¢çš„Python程åº�ä¸çš„函数或方法。
解决方案¶
实现一个远程方法调用的最简å�•æ–¹å¼�是使用XML-RPC。下é�¢æˆ‘们演示一下一个实现了键-值å˜å‚¨åŠŸèƒ½çš„ç®€å�•æœ�务器:
from xmlrpc.server import SimpleXMLRPCServer
class KeyValueServer:
_rpc_methods_ = ['get', 'set', 'delete', 'exists', 'keys']
def __init__(self, address):
self._data = {}
self._serv = SimpleXMLRPCServer(address, allow_none=True)
for name in self._rpc_methods_:
self._serv.register_function(getattr(self, name))
def get(self, name):
return self._data[name]
def set(self, name, value):
self._data[name] = value
def delete(self, name):
del self._data[name]
def exists(self, name):
return name in self._data
def keys(self):
return list(self._data)
def serve_forever(self):
self._serv.serve_forever()
# Example
if __name__ == '__main__':
kvserv = KeyValueServer(('', 15000))
kvserv.serve_forever()
下�我们从一个客户端机器上��访问�务器:
>>> from xmlrpc.client import ServerProxy
>>> s = ServerProxy('http://localhost:15000', allow_none=True)
>>> s.set('foo', 'bar')
>>> s.set('spam', [1, 2, 3])
>>> s.keys()
['spam', 'foo']
>>> s.get('foo')
'bar'
>>> s.get('spam')
[1, 2, 3]
>>> s.delete('spam')
>>> s.exists('spam')
False
>>>
讨论¶
XML-RPC å�¯ä»¥è®©æˆ‘ä»¬å¾ˆå®¹æ˜“çš„æž„é€ ä¸€ä¸ªç®€å�•的远程调用æœ�åŠ¡ã€‚ä½ æ‰€éœ€è¦�å�šçš„仅仅是创建一个æœ�务器实例,
通过它的方法 register_function() �注册函数,然�使用方法 serve_forever() �动它。
在上é�¢æˆ‘们将这些æ¥éª¤æ”¾åœ¨ä¸€èµ·å†™åˆ°ä¸€ä¸ªç±»ä¸ï¼Œä¸�够这并ä¸�æ˜¯å¿…é¡»çš„ã€‚æ¯”å¦‚ä½ è¿˜å�¯ä»¥åƒ�下é�¢è¿™æ ·åˆ›å»ºä¸€ä¸ªæœ�务器:
from xmlrpc.server import SimpleXMLRPCServer
def add(x,y):
return x+y
serv = SimpleXMLRPCServer(('', 15000))
serv.register_function(add)
serv.serve_forever()
XML-RPC暴露出æ�¥çš„函数å�ªèƒ½é€‚用于部分数æ�®ç±»åž‹ï¼Œæ¯”如å—符串ã€�æ•´å½¢ã€�列表和å—典。 对于其他类型就得需è¦�å�šäº›é¢�外的功课了。 ä¾‹å¦‚ï¼Œå¦‚æžœä½ æƒ³é€šè¿‡ XML-RPC ä¼ é€’ä¸€ä¸ªå¯¹è±¡å®žä¾‹ï¼Œå®žé™…ä¸Šå�ªæœ‰ä»–的实例å—典被处ç�†ï¼š
>>> class Point:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> p = Point(2, 3)
>>> s.set('foo', p)
>>> s.get('foo')
{'x': 2, 'y': 3}
>>>
类似的,对于二进制数æ�®çš„处ç�†ä¹Ÿè·Ÿä½ 想象的ä¸�å¤ªä¸€æ ·ï¼š
>>> s.set('foo', b'Hello World')
>>> s.get('foo')
<xmlrpc.client.Binary object at 0x10131d410>
>>> _.data
b'Hello World'
>>>
一般æ�¥è®²ï¼Œä½ ä¸�应该将 XML-RPC æœ�务以公共API的方å¼�暴露出æ�¥ã€‚ 对于这ç§�情况,通常分布å¼�应用程åº�会是一个更好的选择。
XML-RPC的一个缺点是它的性能。SimpleXMLRPCServer 的实现是�线程的,
所以它ä¸�适å�ˆäºŽå¤§åž‹ç¨‹åº�,尽管我们在11.2å°�èŠ‚ä¸æ¼”示过它是å�¯ä»¥é€šè¿‡å¤šçº¿ç¨‹æ�¥æ‰§è¡Œçš„。
å�¦å¤–,由于 XML-RPC 将所有数æ�®éƒ½åº�列化为XMLæ ¼å¼�,所以它会比其他的方å¼�è¿�行的慢一些。
但是它也有优点,这ç§�æ–¹å¼�的编ç �å�¯ä»¥è¢«ç»�大部分其他编程è¯è¨€æ”¯æŒ�。
通过使用这ç§�æ–¹å¼�,其他è¯è¨€çš„客户端程åº�éƒ½èƒ½è®¿é—®ä½ çš„æœ�务。
虽然XML-RPCæœ‰å¾ˆå¤šç¼ºç‚¹ï¼Œä½†æ˜¯å¦‚æžœä½ éœ€è¦�快速构建一个简å�•远程过程调用系统的è¯�,它ä»�然值得去å¦ä¹ 的。 有时候,简å�•的方案就已ç»�足够了。