13.11. xmlrpc.client — xml-江南app体育官方入口
目的:用于xml-rpc通信的客户端库。
xml-rpc是建立在http和xml之上的轻量级远程过程调用协议。 xmlrpclib
模块允许python程序与以任何语言编写的xml-rpc服务器进行通信。
本节中的所有示例均使用xmlrpc_server.py
中定义的服务器,该服务器在源代码发行版中可用,并包含在此处以供参考。
xmlrpc_server.py
from xmlrpc.server import simplexmlrpcserver
from xmlrpc.client import binary
import datetime
class exampleservice:
def ping(self):
"""simple function to respond when called
to demonstrate connectivity.
"""
return true
def now(self):
"""returns the server current date and time."""
return datetime.datetime.now()
def show_type(self, arg):
"""illustrates how types are passed in and out of
server methods.
accepts one argument of any type.
returns a tuple with string representation of the value,
the name of the type, and the value itself.
"""
return (str(arg), str(type(arg)), arg)
def raises_exception(self, msg):
"always raises a runtimeerror with the message passed in"
raise runtimeerror(msg)
def send_back_binary(self, bin):
"""accepts single binary argument, and unpacks and
repacks it to return it."""
data = bin.data
print('send_back_binary({!r})'.format(data))
response = binary(data)
return response
if __name__ == '__main__':
server = simplexmlrpcserver(('localhost', 9000),
logrequests=true,
allow_none=true)
server.register_introspection_functions()
server.register_multicall_functions()
server.register_instance(exampleservice())
try:
print('use control-c to exit')
server.serve_forever()
except keyboardinterrupt:
print('exiting')
连接到服务器
将客户端连接到服务器的最简单方法是实例化serverproxy
对象,并为其提供服务器的uri。例如,演示服务器在本地主机的端口9000上运行。
xmlrpc_serverproxy.py
import xmlrpc.client
server = xmlrpc.client.serverproxy('http://localhost:9000')
print('ping:', server.ping())
在这种情况下,服务的ping()
方法不带任何参数并返回单个布尔值。
$ python3 xmlrpc_serverproxy.py
ping: true
其他选项可用于支持替代运输。现成的同时支持 http 和 https,并且都具有基本身份验证。为了实现新的通信通道,只需要一个新的传输类。例如,通过 smtp 实现 xml-rpc 可能是一个有趣的练习。
xmlrpc_serverproxy_verbose.py
import xmlrpc.client
server = xmlrpc.client.serverproxy('http://localhost:9000',
verbose=true)
print('ping:', server.ping())
verbose
选项提供调试信息,可用于解决通信错误。
$ python3 xmlrpc_serverproxy_verbose.py
send: b'post /rpc2 http/1.1..host: localhost:9000..
accept-encoding: gzip..content-type: text/xml..
user-agent: python-xmlrpc/3.5..content-length: 98....'
send: b"..
ping .. . ."
reply: 'http/1.0 200 ok..'
header: server header: date header: content-type header:
content-length body: b"..
..1 .
. . ."
ping: true
如果需要备用系统,则可以从 utf-8 更改默认编码。
xmlrpc_serverproxy_encoding.py
import xmlrpc.client
server = xmlrpc.client.serverproxy('http://localhost:9000',
encoding='iso-8859-1')
print('ping:', server.ping())
服务器自动检测正确的编码。
$ python3 xmlrpc_serverproxy_encoding.py
ping: true
allow_none
选项控制python的none
值是否自动转换为nil值或是否导致错误。
xmlrpc_serverproxy_allow_none.py
import xmlrpc.client
server = xmlrpc.client.serverproxy('http://localhost:9000',
allow_none=false)
try:
server.show_type(none)
except typeerror as err:
print('error:', err)
server = xmlrpc.client.serverproxy('http://localhost:9000',
allow_none=true)
print('allowed:', server.show_type(none))
如果客户端不允许none
,则会在本地引发错误,但如果未将其配置为允许none
,则也可以从服务器内部引发该错误。
$ python3 xmlrpc_serverproxy_allow_none.py
error: cannot marshal none unless allow_none is enabled
allowed: ['none', "", none]
数据类型
xml-rpc 协议可识别一组有限的通用数据类型。这些类型可以作为参数或返回值传递,并可以组合以创建更复杂的数据结构。
xmlrpc_types.py
import xmlrpc.client
import datetime
server = xmlrpc.client.serverproxy('http://localhost:9000')
data = [
('boolean', true),
('integer', 1),
('float', 2.5),
('string', 'some text'),
('datetime', datetime.datetime.now()),
('array', ['a', 'list']),
('array', ('a', 'tuple')),
('structure', {'a': 'dictionary'}),
]
for t, v in data:
as_string, type_name, value = server.show_type(v)
print('{:<12}: {}'.format(t, as_string))
print('{:12} {}'.format('', type_name))
print('{:12} {}'.format('', value))
简单类型是:
$ python3 xmlrpc_types.py
boolean : true
true
integer : 1
1
float : 2.5
2.5
string : some text
some text
datetime : 20160618t19:31:47
20160618t19:31:47
array : ['a', 'list']
['a', 'list']
array : ['a', 'tuple']
['a', 'tuple']
structure : {'a': 'dictionary'}
{'a': 'dictionary'}
可以嵌套支持的类型以创建任意复杂度的值。
xmlrpc_types_nested.py
import xmlrpc.client
import datetime
import pprint
server = xmlrpc.client.serverproxy('http://localhost:9000')
data = {
'boolean': true,
'integer': 1,
'floating-point number': 2.5,
'string': 'some text',
'datetime': datetime.datetime.now(),
'array1': ['a', 'list'],
'array2': ('a', 'tuple'),
'structure': {'a': 'dictionary'},
}
arg = []
for i in range(3):
d = {}
d.update(data)
d['integer'] = i
arg.append(d)
print('before:')
pprint.pprint(arg, width=40)
print('.after:')
pprint.pprint(server.show_type(arg)[-1], width=40)
该程序将包含所有受支持类型的词典列表传递到示例服务器,该服务器返回数据。元组将转换为列表,并且datetime
实例将转换为datetime
对象,但否则数据将保持不变。
$ python3 xmlrpc_types_nested.py
before:
[{'array': ('a', 'tuple'),
'boolean': true,
'datetime': datetime.datetime(2016, 6, 18, 19, 27, 30, 45333),
'floating-point number': 2.5,
'integer': 0,
'string': 'some text',
'structure': {'a': 'dictionary'}},
{'array': ('a', 'tuple'),
'boolean': true,
'datetime': datetime.datetime(2016, 6, 18, 19, 27, 30, 45333),
'floating-point number': 2.5,
'integer': 1,
'string': 'some text',
'structure': {'a': 'dictionary'}},
{'array': ('a', 'tuple'),
'boolean': true,
'datetime': datetime.datetime(2016, 6, 18, 19, 27, 30, 45333),
'floating-point number': 2.5,
'integer': 2,
'string': 'some text',
'structure': {'a': 'dictionary'}}]
after:
[{'array': ['a', 'tuple'],
'boolean': true,
'datetime': ,
'floating-point number': 2.5,
'integer': 0,
'string': 'some text',
'structure': {'a': 'dictionary'}},
{'array': ['a', 'tuple'],
'boolean': true,
'datetime': ,
'floating-point number': 2.5,
'integer': 1,
'string': 'some text',
'structure': {'a': 'dictionary'}},
{'array': ['a', 'tuple'],
'boolean': true,
'datetime': ,
'floating-point number': 2.5,
'integer': 2,
'string': 'some text',
'structure': {'a': 'dictionary'}}]
xml-rpc 支持将日期作为本机类型,并且xmlrpclib
可以使用两个类之一来表示传出代理中或从服务器接收到的日期值。
xmlrpc_serverproxy_use_datetime.py
import xmlrpc.client
server = xmlrpc.client.serverproxy('http://localhost:9000',
use_datetime=true)
now = server.now()
print('with:', now, type(now), now.__class__.__name__)
server = xmlrpc.client.serverproxy('http://localhost:9000',
use_datetime=false)
now = server.now()
print('without:', now, type(now), now.__class__.__name__)
默认情况下,使用内部版本的datetime
,但是use_datetime
选项打开支持使用模块。
$ python3 source/xmlrpc.client/xmlrpc_serverproxy_use_datetime.py
with: 2016-06-18 19:18:31 datetime
without: 20160618t19:18:31 datetime
传递对象
python 类的实例被视为结构,并作为字典传递,而对象的属性作为字典中的值。
xmlrpc_types_object.py
import xmlrpc.client
import pprint
class myobj:
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return 'myobj({!r}, {!r})'.format(self.a, self.b)
server = xmlrpc.client.serverproxy('http://localhost:9000')
o = myobj(1, 'b goes here')
print('o :', o)
pprint.pprint(server.show_type(o))
o2 = myobj(2, o)
print('.o2 :', o2)
pprint.pprint(server.show_type(o2))
传递对象
python 类的实例被视为结构,并作为字典传递,而对象的属性作为字典中的值。
xmlrpc_types_object.py
导入xmlrpc.client
导入pprint
myobj类:
def __init __(self,a,b):
self.a = a
self.b = b
def __repr __(自己):
返回'myobj({!r},{!r})'。format(self.a,self.b)
服务器= xmlrpc.client.serverproxy('http:/// localhost:9000')
o = myobj(1,'b去这里')
打印('o:',o)
pprint.pprint(server.show_type(o))
o2 = myobj(2,o)
print('。o2:',o2)
pprint.pprint(server.show_type(o2))
当该值从服务器发送回客户端时,结果是客户端上的字典,因为值中没有任何编码来告诉服务器(或客户端)应将其实例化为类的一部分。
$ python3 xmlrpc_types_object.py
o : myobj(1, 'b goes here')
["{'b': 'b goes here', 'a': 1}", "",
{'a': 1, 'b': 'b goes here'}]
o2 : myobj(2, myobj(1, 'b goes here'))
["{'b': {'b': 'b goes here', 'a': 1}, 'a': 2}",
"",
{'a': 2, 'b': {'a': 1, 'b': 'b goes here'}}]
二进制数据
传递给服务器的所有值都将被编码并自动转义。但是,某些数据类型可能包含无效的 xml 字符。例如,二进制图像数据可能包括 ascii 控制范围为 0 到 31 的字节值。要传递二进制数据,最好使用binary
类对其进行编码以进行传输。
xmlrpc_binary.py
import xmlrpc.client
import xml.parsers.expat
server = xmlrpc.client.serverproxy('http://localhost:9000')
s = b'this is a string with control characters.00'
print('local string:', s)
data = xmlrpc.client.binary(s)
response = server.send_back_binary(data)
print('as binary:', response.data)
try:
print('as string:', server.show_type(s))
except xml.parsers.expat.expaterror as err:
print('.error:', err)
如果将包含 null 字节的字符串传递给show_type()
,则 xml 解析器在处理响应时会引发异常。
$ python3 xmlrpc_binary.py
local string: b'this is a string with control characters.00'
as binary: b'this is a string with control characters.00'
error: not well-formed (invalid token): line 6, column 55
binary
对象还可以用于通过 。与通过网络发送多少可执行代码有关的常规安全问题在这里适用(即除非通信通道安全,否则不要这样做)。
import xmlrpc.client
import pickle
import pprint
class myobj:
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return 'myobj({!r}, {!r})'.format(self.a, self.b)
server = xmlrpc.client.serverproxy('http://localhost:9000')
o = myobj(1, 'b goes here')
print('local:', id(o))
print(o)
print('.as object:')
pprint.pprint(server.show_type(o))
p = pickle.dumps(o)
b = xmlrpc.client.binary(p)
r = server.send_back_binary(b)
o2 = pickle.loads(r.data)
print('.from pickle:', id(o2))
pprint.pprint(o2)
binary
实例的data属性包含该对象的 pickled 版本,因此必须先对其进行 pickled 才能使用它。这导致另一个对象(具有新的id值)。
$ python3 xmlrpc_binary_pickle.py
local: 4327262304
myobj(1, 'b goes here')
as object:
["{'a': 1, 'b': 'b goes here'}", "",
{'a': 1, 'b': 'b goes here'}]
from pickle: 4327262472
myobj(1, 'b goes here')
异常处理
由于 xml-rpc 服务器可以用任何语言编写,因此无法直接传输异常类。相反,服务器中引发的异常将转换为fault
对象,并在客户端本地作为异常引发。
xmlrpc_exception.py
import xmlrpc.client
server = xmlrpc.client.serverproxy('http://localhost:9000')
try:
server.raises_exception('a message')
except exception as err:
print('fault code:', err.faultcode)
print('message :', err.faultstring)
原始错误消息保存在faultstring
属性中,并且faultcode
设置为 xml-rpc 错误号。
$ python3 xmlrpc_exception.py
fault code: 1
message : :a message
将呼叫合并为一条消息
多重调用是 xml-rpc 协议的扩展,它允许同时发送多个调用,并收集响应并将其返回给调用者。
xmlrpc_multicall.py
import xmlrpc.client
server = xmlrpc.client.serverproxy('http://localhost:9000')
multicall = xmlrpc.client.multicall(server)
multicall.ping()
multicall.show_type(1)
multicall.show_type('string')
for i, r in enumerate(multicall()):
print(i, r)
要使用multicall
实例,请像使用serverproxy
一样调用其上的方法,然后调用不带参数的对象以实际运行远程功能。返回值是一个迭代器,它从所有调用中产生结果。
$ python3 xmlrpc_multicall.py
0 true
1 ['1', "", 1]
2 ['string', "", 'string']
如果其中一个调用导致fault
,则当从迭代器生成结果并且没有更多结果可用时,将引发异常。
xmlrpc_multicall_exception.py
import xmlrpc.client
server = xmlrpc.client.serverproxy('http://localhost:9000')
multicall = xmlrpc.client.multicall(server)
multicall.ping()
multicall.show_type(1)
multicall.raises_exception('next to last call stops execution')
multicall.show_type('string')
try:
for i, r in enumerate(multicall()):
print(i, r)
except xmlrpc.client.fault as err:
print('error:', err)
由于来自raises_exception()
的第三个响应会生成异常,因此无法访问来自show_type()
的响应。
$ python3 xmlrpc_multicall_exception.py
0 true
1 ['1', "", 1]
error: :next to last call stops execution">
也可以看看
- – xml-rpc服务器实现。
- – http服务器实施。
- – 介绍如何使用xml-rpc来以多种语言实现客户端和服务器。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 cc 协议,如果我们的工作有侵犯到您的权益,请及时联系江南app体育官方入口。