Python的XMLRPC简介及小技巧


类型:Python,创建时间:Jan. 1, 2012, 2:30 p.m.

标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/50/。

我觉得,SimpleXMLRPCServer模块可以说是Python的招牌菜。

编写客户端提交数据到服务器处理是程序员最常碰到的几个问题之一。各种不同的语言对此都有相应的解决方案。比如Unix下,C程序员们可以用SUNRPC,Java程序员则使用RMI来处理。大多数语言还都可以使用Web Service或者ICE。它们的使用方法类似,编写一个接口定义文件,用一个工具处理并生成代码,加入到工程中,最后编译生成目标文件运行。有用过这类工具的朋友们,脑子里应该都会闪出一个字——烦!真的是谁用谁知道。

Python同样也提供了一个基于XMLRPC的解决方案,不过用法很简单:

  1. 首先,就像在编写普通的程序那样子编写服务器。
  2. 接着使用SimpleXMLRPCServer模块运行XMLRPC服务器,在其中注册服务器提供的函数或者对象。
  3. 最后,在客户端内使用xmlrpclib.ServerProxy连接到服务器,想要调用服务器的函数,直接调用ServerProxy即可。

一个最简单的hello,word示例:

#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.pyhelloclient.py就可以看到控制台输出hello,world!

不过,美中不足的是,SimpleXMLRPCServer是一个单线程的服务器。这意味着,如果几个客户端同时发出多个请求,其它的请求就必须等待第一个请求完成以后才能继续。这里有个技巧解决这个问题:

from SimpleXMLRPCServer import SimpleXMLRPCServer
from SocketServer import ThreadingMixIn
class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    pass

现在把helloserver.py改一改:

svr=ThreadXMLRPCServer(("", 8080), allow_none=True)

现在服务器就支持多线程并发了。

XMLRPC一个标准协议,定义了如何使用HTTP和XML来传递多种类型数据。据我观察,xmlrpclib对于日期/时间类型的有特殊的支持。假如有一个服务器提供的函数是:

def toluar(d):
    pass

这原本是一个将阳历转换成阴历的函数。要求ddatetime模块里的datetime类型。虽然客户端确实传入的确实是datetime类型,服务器却会将其解释为xmlrpclib.DateTime类型。 解决办法是:

class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    #从SimpleXMLRPCServer模块抄出来的代码
    def _marshaled_dispatch(self, data, dispatch_method = None):
        try:
            #唯一的改动是这里加了一个use_datetime
            params, method = xmlrpclib.loads(data, use_datetime=True)

            # generate response
            if dispatch_method is not None:
                response = dispatch_method(method, params)
            else:
                response = self._dispatch(method, params)
            # wrap response in a singleton tuple
            response = (response,)
            response = xmlrpclib.dumps(response, methodresponse=1,
                    allow_none=self.allow_none, encoding=self.encoding)
        except Fault, fault:
            response = xmlrpclib.dumps(fault, allow_none=self.allow_none,
                    encoding=self.encoding)
        except:
            # report exception back to server
            exc_type, exc_value, exc_tb = sys.exc_info()
            response = xmlrpclib.dumps(
                    xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value)),
                    encoding=self.encoding, allow_none=self.allow_none,
                    )

        return response

svr=ThreadXMLRPCServer(("", 8080), allow_none=True)

客户端方面则比较简单:

svr=ServerProxy("http://localhost:8080/", allow_none=True, use_datetime=True)

注意 use_datetime参数默认是False

标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/50/。


A1233(Jan. 2, 2012, 8:22 a.m.)

您好,我在您的blog上拜读了您的文章,在我的实际项目中正好用到,其中发现了让自己疑惑的问题,能帮我指点一下吗?QQ:346264877 请指教

panda(March 23, 2012, 8:32 p.m.)

ThreadingMixIn要注意MixInI是大写的。


何不来发表一下您对本文的看法(使用Markdown语法,分段空两行):