• 11.6 通过XML-RPC实现简单的远程调用
    • 问题
    • 解决方案
    • 讨论

    11.6 通过XML-RPC实现简单的远程调用

    问题

    你想找到一个简单的方式去执行运行在远程机器上面的Python程序中的函数或方法。

    解决方案

    实现一个远程方法调用的最简单方式是使用XML-RPC。下面我们演示一下一个实现了键-值存储功能的简单服务器:

    1. from xmlrpc.server import SimpleXMLRPCServer
    2.  
    3. class KeyValueServer:
    4. _rpc_methods_ = ['get', 'set', 'delete', 'exists', 'keys']
    5. def __init__(self, address):
    6. self._data = {}
    7. self._serv = SimpleXMLRPCServer(address, allow_none=True)
    8. for name in self._rpc_methods_:
    9. self._serv.register_function(getattr(self, name))
    10.  
    11. def get(self, name):
    12. return self._data[name]
    13.  
    14. def set(self, name, value):
    15. self._data[name] = value
    16.  
    17. def delete(self, name):
    18. del self._data[name]
    19.  
    20. def exists(self, name):
    21. return name in self._data
    22.  
    23. def keys(self):
    24. return list(self._data)
    25.  
    26. def serve_forever(self):
    27. self._serv.serve_forever()
    28.  
    29. # Example
    30. if __name__ == '__main__':
    31. kvserv = KeyValueServer(('', 15000))
    32. kvserv.serve_forever()

    下面我们从一个客户端机器上面来访问服务器:

    1. >>> from xmlrpc.client import ServerProxy
    2. >>> s = ServerProxy('http://localhost:15000', allow_none=True)
    3. >>> s.set('foo', 'bar')
    4. >>> s.set('spam', [1, 2, 3])
    5. >>> s.keys()
    6. ['spam', 'foo']
    7. >>> s.get('foo')
    8. 'bar'
    9. >>> s.get('spam')
    10. [1, 2, 3]
    11. >>> s.delete('spam')
    12. >>> s.exists('spam')
    13. False
    14. >>>

    讨论

    XML-RPC 可以让我们很容易的构造一个简单的远程调用服务。你所需要做的仅仅是创建一个服务器实例,通过它的方法 register_function() 来注册函数,然后使用方法 serve_forever() 启动它。在上面我们将这些步骤放在一起写到一个类中,不够这并不是必须的。比如你还可以像下面这样创建一个服务器:

    1. from xmlrpc.server import SimpleXMLRPCServer
    2. def add(x,y):
    3. return x+y
    4.  
    5. serv = SimpleXMLRPCServer(('', 15000))
    6. serv.register_function(add)
    7. serv.serve_forever()

    XML-RPC暴露出来的函数只能适用于部分数据类型,比如字符串、整形、列表和字典。对于其他类型就得需要做些额外的功课了。例如,如果你想通过 XML-RPC 传递一个对象实例,实际上只有他的实例字典被处理:

    1. >>> class Point:
    2. ... def __init__(self, x, y):
    3. ... self.x = x
    4. ... self.y = y
    5. ...
    6. >>> p = Point(2, 3)
    7. >>> s.set('foo', p)
    8. >>> s.get('foo')
    9. {'x': 2, 'y': 3}
    10. >>>

    类似的,对于二进制数据的处理也跟你想象的不太一样:

    1. >>> s.set('foo', b'Hello World')
    2. >>> s.get('foo')
    3. <xmlrpc.client.Binary object at 0x10131d410>
    4.  
    5. >>> _.data
    6. b'Hello World'
    7. >>>

    一般来讲,你不应该将 XML-RPC 服务以公共API的方式暴露出来。对于这种情况,通常分布式应用程序会是一个更好的选择。

    XML-RPC的一个缺点是它的性能。SimpleXMLRPCServer 的实现是单线程的,所以它不适合于大型程序,尽管我们在11.2小节中演示过它是可以通过多线程来执行的。另外,由于 XML-RPC 将所有数据都序列化为XML格式,所以它会比其他的方式运行的慢一些。但是它也有优点,这种方式的编码可以被绝大部分其他编程语言支持。通过使用这种方式,其他语言的客户端程序都能访问你的服务。

    虽然XML-RPC有很多缺点,但是如果你需要快速构建一个简单远程过程调用系统的话,它仍然值得去学习的。有时候,简单的方案就已经足够了。

    原文:

    http://python3-cookbook.readthedocs.io/zh_CN/latest/c11/p06_implement_simple_remote_procedure_call_with_xml_rpc.html