第十四题地址:http://www.pythonchallenge.com/pc/return/disproportional.html
题目中的图片,点击数字5跳转到新地址: http://www.pythonchallenge.com/pc/phonebook.php。得到一个XML文档。
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value>
<int>105</int>
</value>
</member>
<member>
<name>faultString</name>
<value>
<string>
XML error: Invalid document end at line 1, column 1
</string>
</value>
</member>
</struct>
</value>
</fault>
</methodResponse>
然后我们在图片下面还知道要我们做的是phone that evil。Evil是什么呢,在之前的那题中,我们知道evil就是Bert。(网上都说用IE浏览器可以看到,但是我还是只能在命令行返回值中得到这个结果。)
对于一个XML文档,我们怎么进行操作呢。搜索得到的理由是因为这题用到了RPC - Remote Procedure Call的协议,然后python标准库中有xmlrpclib这个模块。在python 3x中被更名为xmlrpc.client。
那么接下来,我们就导入xmlrpclib然后对XML进行操作。
import xmlrpclib
connect = xmlrpclib.ServerProxy("http://www.pythonchallenge.com/pc/phonebook.php")
print connect.system.listMethods()
# ['phone', 'system.listMethods', 'system.methodHelp', 'system.methodSignature', 'system.multicall', 'system.getCapabilities']
print connect.system.methodHelp("phone")
# Returns the phone of a person
print connect.phone("Bert")
# 555-ITALY
上述的方法会在接下来详细讲述。最后得到的结果是 555-ITALY。但是关键词只需要ITALY,但是提示是SMALL letters, 所以是italy。
####################################################################################################################################
RPC protocol
Remote Procedure Call Protocol - 远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,比如TCP或者UDP,为通信过程之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
工作原理:
1. 调用客户端句柄;执行传送参数
2. 调用本地系统内核发送网络消息
3. 消息传送到远程主机
4. 服务器句柄得到消息并取得参数
5. 执行远程过程
6. 执行的过程将结果返回服务器句柄
7. 服务器句柄返回结果,调用远程系统内核
8. 消息传回本地主机
9. 客户句柄由内核接收消息
10. 客户接收句柄返回的数据
python xmlrpclib 模块
XML-RPC is a Remote Procedure Call method that uses XML passed via HTTP as a transport. With it, a client can call methods with parameters on a remote server (the server is named by a URI) and get back structured data. This module supports writing XML-RPC client code; it handles all the details of translating between conformable Python objects and XML on the wire.
XML-RPC 是 Remote Procedure Call 方法,使用XML通过HTTP传输。使用XML-RPC,一个客户端可以在远程的服务器上(服务器使用URI命名)用参数调用方法,并得到结构化的数据返回值。Python xmlrpclib模块支持XML-RPC客户端代码,支持所有的Python对象和XML之间的转换。
比较关键的ServerProxy对象
ServerProxy.system.listMethods()
返回一个list,里面存着的都是String,都是支持XML-RPC server 的方法。
ServerProxy.system.methodSignature(name)
传入一个方法名作为参数,返回方法可能的signatures。一个signature就是一个types类型的数组集合。第一个类型就是方法返回值的类型,其他的是参数的类型。因为多种signatures是被允许的(overloading),所以这个方法返回一串signatures,而不是单一singleton。
Signatures,比如一个方法需要一个array作为参数,返回一个string。那么方法返回的是“string,array”。如果是需要3个integers作为参数,返回一个string,那么方法的返回值是“string,int,int,int”。
如果方法没有定义signature,那么返回non-array。Python中,这意味着返回值回是任何,但是不是list。
ServerProxy.system.methodHelp(name)
传入一个方法名作为参数,返回方法的具体使用描述。如果没有描述,那么就返回一个空的string。这个string描述文档可以包含HTML的修饰。
其他还有Boolean,DateTime, Binary, Fault, ProtocolError, MultiCall等对象,具体的描述请看参考中的Python文档链接。
一个调用了xmlrpclib模块的简单Hello World示例:
#helloserver.py
from SimpleXMLRPCServer import SimpleXMLRPCServer
def hello():
print "hello,world!"
svr=SimpleXMLRPCServer(("", 8080), allow_none=True)
svr.register_function(hello)
svr.serve_forever()
#helloclient.py
from xmlrpclib import ServerProxy
svr=ServerProxy("http://localhost:8080")
svr.hello()
对于上述的代码,我们先运行helloserver.py,然后运行helloclient.py,可以再控制台输出hello,world!
127.0.0.1 - - [29/Nov/2014 23:21:43] "POST /RPC2 HTTP/1.1" 200 -
hello,world!
P.S. 处理并发
SimpleXMLRPCServer是一个单线程的服务器。意味着如果几个客户端同事发出多个请求,那么并需等待第一个请求完成之后才能继续,下面技巧解决此类问题:
from SimpleXMLRPCServer import SimpleXMLRPCServer
from SocketServer import ThreadingMixIn
class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
pass
把helloserver.py改一改:
svr=ThreadXMLRPCServer(("", 8080), allow_none=True)
然后服务器就支持多线程并发了。
参考:
http://en.wikipedia.org/wiki/Remote_procedure_call
http://baike.baidu.com/view/7287257.htm?fromtitle=RPC%E5%8D%8F%E8%AE%AE&fromid=5019569&type=syn
https://docs.python.org/2/library/xmlrpclib.html
http://hgoldfish.com/blogs/article/50/
http://my.oschina.net/sanpeterguo/blog/100593