Skip to content

Commit 5f4fa9e

Browse files
committed
11.06 小节完成~
1 parent 69082f1 commit 5f4fa9e

File tree

1 file changed

+110
-108
lines changed

1 file changed

+110
-108
lines changed

source/c11/p06_implement_simple_remote_procedure_call_with_xml_rpc.rst

Lines changed: 110 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -5,123 +5,125 @@
55
----------
66
问题
77
----------
8-
You want an easy way to execute functions or methods in Python programs running on
9-
remote machines.
8+
你想找到一个简单的方式去执行运行在远程机器上面的Python程序中的函数或方法。
109

1110
|
1211
1312
----------
1413
解决方案
1514
----------
16-
Perhaps the easiest way to implement a simple remote procedure call mechanism is to
17-
use XML-RPC. Here is an example of a simple server that implements a simple key-
18-
value store:
19-
20-
from xmlrpc.server import SimpleXMLRPCServer
21-
22-
class KeyValueServer:
23-
_rpc_methods_ = ['get', 'set', 'delete', 'exists', 'keys']
24-
def __init__(self, address):
25-
self._data = {}
26-
self._serv = SimpleXMLRPCServer(address, allow_none=True)
27-
for name in self._rpc_methods_:
28-
self._serv.register_function(getattr(self, name))
29-
30-
def get(self, name):
31-
return self._data[name]
32-
33-
def set(self, name, value):
34-
self._data[name] = value
35-
36-
def delete(self, name):
37-
del self._data[name]
38-
39-
def exists(self, name):
40-
return name in self._data
41-
42-
def keys(self):
43-
return list(self._data)
44-
45-
def serve_forever(self):
46-
self._serv.serve_forever()
47-
48-
# Example
49-
if __name__ == '__main__':
50-
kvserv = KeyValueServer(('', 15000))
51-
kvserv.serve_forever()
52-
53-
Here is how you would access the server remotely from a client:
54-
55-
>>> from xmlrpc.client import ServerProxy
56-
>>> s = ServerProxy('http://localhost:15000', allow_none=True)
57-
>>> s.set('foo', 'bar')
58-
>>> s.set('spam', [1, 2, 3])
59-
>>> s.keys()
60-
['spam', 'foo']
61-
>>> s.get('foo')
62-
'bar'
63-
>>> s.get('spam')
64-
[1, 2, 3]
65-
>>> s.delete('spam')
66-
>>> s.exists('spam')
67-
False
68-
>>>
15+
实现一个远程方法调用的最简单方式是使用XML-RPC。下面我们演示一下一个实现了键-值存储功能的简单服务器:
16+
17+
.. code-block:: python
18+
19+
from xmlrpc.server import SimpleXMLRPCServer
20+
21+
class KeyValueServer:
22+
_rpc_methods_ = ['get', 'set', 'delete', 'exists', 'keys']
23+
def __init__(self, address):
24+
self._data = {}
25+
self._serv = SimpleXMLRPCServer(address, allow_none=True)
26+
for name in self._rpc_methods_:
27+
self._serv.register_function(getattr(self, name))
28+
29+
def get(self, name):
30+
return self._data[name]
31+
32+
def set(self, name, value):
33+
self._data[name] = value
34+
35+
def delete(self, name):
36+
del self._data[name]
37+
38+
def exists(self, name):
39+
return name in self._data
40+
41+
def keys(self):
42+
return list(self._data)
43+
44+
def serve_forever(self):
45+
self._serv.serve_forever()
46+
47+
# Example
48+
if __name__ == '__main__':
49+
kvserv = KeyValueServer(('', 15000))
50+
kvserv.serve_forever()
51+
52+
下面我们从一个客户端机器上面来访问服务器:
53+
54+
.. code-block:: python
55+
56+
>>> from xmlrpc.client import ServerProxy
57+
>>> s = ServerProxy('http://localhost:15000', allow_none=True)
58+
>>> s.set('foo', 'bar')
59+
>>> s.set('spam', [1, 2, 3])
60+
>>> s.keys()
61+
['spam', 'foo']
62+
>>> s.get('foo')
63+
'bar'
64+
>>> s.get('spam')
65+
[1, 2, 3]
66+
>>> s.delete('spam')
67+
>>> s.exists('spam')
68+
False
69+
>>>
6970
7071
|
7172
7273
----------
7374
讨论
7475
----------
75-
XML-RPC can be an extremely easy way to set up a simple remote procedure call service.
76-
All you need to do is create a server instance, register functions with it using the regis
77-
ter_function() method, and then launch it using the serve_forever() method. This
78-
recipe packages it up into a class to put all of the code together, but there is no such
79-
requirement. For example, you could create a server by trying something like this:
80-
81-
from xmlrpc.server import SimpleXMLRPCServer
82-
def add(x,y):
83-
return x+y
84-
85-
serv = SimpleXMLRPCServer(('', 15000))
86-
serv.register_function(add)
87-
serv.serve_forever()
88-
89-
Functions exposed via XML-RPC only work with certain kinds of data such as strings,
90-
numbers, lists, and dictionaries. For everything else, some study is required. For in‐
91-
stance, if you pass an instance through XML-RPC, only its instance dictionary is
92-
handled:
93-
94-
>>> class Point:
95-
... def __init__(self, x, y):
96-
... self.x = x
97-
... self.y = y
98-
...
99-
>>> p = Point(2, 3)
100-
>>> s.set('foo', p)
101-
>>> s.get('foo')
102-
{'x': 2, 'y': 3}
103-
>>>
104-
105-
Similarly, handling of binary data is a bit different than you expect:
106-
107-
>>> s.set('foo', b'Hello World')
108-
>>> s.get('foo')
109-
<xmlrpc.client.Binary object at 0x10131d410>
110-
111-
>>> _.data
112-
b'Hello World'
113-
>>>
114-
115-
As a general rule, you probably shouldn’t expose an XML-RPC service to the rest of the
116-
world as a public API. It often works best on internal networks where you might want
117-
to write simple distributed programs involving a few different machines.
118-
A downside to XML-RPC is its performance. The SimpleXMLRPCServer implementa‐
119-
tion is only single threaded, and wouldn’t be appropriate for scaling a large application,
120-
although it can be made to run multithreaded, as shown in Recipe 11.2. Also, since
121-
XML-RPC serializes all data as XML, it’s inherently slower than other approaches.
122-
However, one benefit of this encoding is that it’s understood by a variety of other pro‐
123-
gramming languages. By using it, clients written in languages other than Python will be
124-
able to access your service.
125-
Despite its limitations, XML-RPC is worth knowing about if you ever have the need to
126-
make a quick and dirty remote procedure call system. Oftentimes, the simple solution
127-
is good enough.
76+
XML-RPC 可以让我们很容易的构造一个简单的远程调用服务。你所需要做的仅仅是创建一个服务器实例,
77+
通过它的方法 ``register_function()`` 来注册函数,然后使用方法 ``serve_forever()`` 启动它。
78+
在上面我们将这些步骤放在一起写到一个类中,不够这并不是必须的。比如你还可以像下面这样创建一个服务器:
79+
80+
.. code-block:: python
81+
82+
from xmlrpc.server import SimpleXMLRPCServer
83+
def add(x,y):
84+
return x+y
85+
86+
serv = SimpleXMLRPCServer(('', 15000))
87+
serv.register_function(add)
88+
serv.serve_forever()
89+
90+
XML-RPC暴露出来的函数只能适用于部分数据类型,比如字符串、整形、列表和字典。
91+
对于其他类型就得需要做些额外的功课了。
92+
例如,如果你想通过 XML-RPC 传递一个对象实例,实际上只有他的实例字典被处理:
93+
94+
.. code-block:: python
95+
96+
>>> class Point:
97+
... def __init__(self, x, y):
98+
... self.x = x
99+
... self.y = y
100+
...
101+
>>> p = Point(2, 3)
102+
>>> s.set('foo', p)
103+
>>> s.get('foo')
104+
{'x': 2, 'y': 3}
105+
>>>
106+
107+
类似的,对于二进制数据的处理也跟你想象的不太一样:
108+
109+
.. code-block:: python
110+
111+
>>> s.set('foo', b'Hello World')
112+
>>> s.get('foo')
113+
<xmlrpc.client.Binary object at 0x10131d410>
114+
115+
>>> _.data
116+
b'Hello World'
117+
>>>
118+
119+
一般来讲,你不应该将 XML-RPC 服务以公共API的方式暴露出来。
120+
对于这种情况,通常分布式应用程序会是一个更好的选择。
121+
122+
XML-RPC的一个缺点是它的性能。``SimpleXMLRPCServer`` 的实现是单线程的,
123+
所以它不适合于大型程序,尽管我们在11.2小节中演示过它是可以通过多线程来执行的。
124+
另外,由于 XML-RPC 将所有数据都序列化为XML格式,所以它会比其他的方式运行的慢一些。
125+
但是它也有优点,这种方式的编码可以被绝大部分其他编程语言支持。
126+
通过使用这种方式,其他语言的客户端程序都能访问你的服务。
127+
128+
虽然XML-RPC有很多缺点,但是如果你需要快速构建一个简单远程过程调用系统的话,它仍然值得去学习的。
129+
有时候,简单的方案就已经足够了。

0 commit comments

Comments
 (0)