用XMLRPC开服务进行server/client通信
Posted yxysuanfa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用XMLRPC开服务进行server/client通信相关的知识,希望对你有一定的参考价值。
本文讲一下怎样用python的xmlrpc开服务,进行server/client的通信。
应用场景:1)需多client訪问应用程序给予应答情况——网页服务。 2)数据极大,希望载入一次。后面仅仅用方法调用
解决方式: 开两个服务。一个数据服务,一个网络服务;数据服务端载入数据。网络服务端调用数据,并将结果显示在网络服务中;
外部调用网络服务返回结果;
应用工具:xmlrpc。本文中以python 2.7.3的xmlrpclib为例,其它语言也有对应接口
以下分别说明。
1. 数据端
在本地localhost的8000端口开server服务,load数据,并定义接口查找数据第i个元素(findai).
Server :
from SimpleXMLRPCServer import SimpleXMLRPCServer global a def load(): global a a = [1 ,2, 24] return a def findai(i): global a print a[i] return a[i] server = SimpleXMLRPCServer(("localhost", 8000)) server.register_function(findai,"findai") load() server.serve_forever()
Client:
import xmlrpclib proxy = xmlrpclib.ServerProxy("http://localhost:8000/") candidate = proxy.findai(1) print "the %d-th number of a is %d" %(1, candidate)
2. 数据端 + 网络端
Client:
import xmlrpclib proxy = xmlrpclib.ServerProxy("http://localhost:8000/") candidate = proxy.findai(1) print "the %d-th number of a is %d" %(1, candidate) from bottle import route, run, template @route(‘/hello/<name>‘) def index(name): return template(‘<b> hello {{name}} </b>‘, name=candidate) run(host="localhost", port=8086)
注意事项:
1. 通信数据类型
注意通讯数据类型仅仅能是python的built-in类型(而不能是numpy类型),所以其它类型应转换为str类型(client端用ast.literal_eval从str转回来)或者更方便的用list(直接server端tolist转,client端numpy.array解)。
否则会报错:
xmlrpclib.Fault: <Fault 8002: "Can‘t serialize output: cannot marshal <type ‘numpy.float64‘> objects">
以string为例(事实上tolist更简单),
Server:
from SimpleXMLRPCServer import SimpleXMLRPCServer global a import ast from cStringIO import StringIO from numpy.lib import format import numpy class T: def to_string(self,arr): f = StringIO() if type(arr)==numpy.ndarray: format.write_array(f,arr) s = f.getvalue() elif isinstance(arr,str)==False: s = str(arr) return s def from_string(self,s): if s[0]!="[": # converted from numpy array f = StringIO(s) arr = format.read_array(f) else: arr = ast.literal_eval(s) return arr def load(self): global a a = [1 ,2, 24] return a def ret_a(self): global a return a server = SimpleXMLRPCServer(("localhost", 8002)) server.register_instance(T()) srv = T() srv.load() server.serve_forever()
Client:
import xmlrpclib proxy = xmlrpclib.ServerProxy("http://localhost:8002/") candidate = proxy.ret_a() print "the variable ‘a‘ in server is "+ str((proxy.from_string(candidate)))
2. 通讯字符编码问题
注意通讯字符必须是unicode编码。用中文的时候要小心。
所以中文的case下,在server段运行:
def gbk_to_unicode(s): return s.decode(‘gbk‘).encode(‘utf-8‘).decode(‘latin1‘)
client端运行:
def unicode_to_gbk(s): return s.encode(‘latin1‘).decode(‘utf-8‘).encode(‘gbk‘)
for example,
Server:
from SimpleXMLRPCServer import SimpleXMLRPCServer global a import ast from cStringIO import StringIO from numpy.lib import format import numpy import sys def gbk_to_unicode(s): return s.decode(‘gbk‘).encode(‘utf-8‘).decode(‘latin1‘) class T: def load(self): # load a dictionary with gbk elements global a a = {"1,1":["小","苹果"],"1,2":[1,2]} def printf(self,s): # receive unicode, return unicode print "received string : "+ s #unicode return s def idx(self,s): # transfer gbk -> unicode to client global a return [gbk_to_unicode(x) for x in a.get(s,[])] reload(sys) sys.setdefaultencoding(‘gbk‘) server = SimpleXMLRPCServer(("localhost", 8002)) server.register_instance(T()) srv = T() srv.load() server.serve_forever()
Client:
import xmlrpclib proxy = xmlrpclib.ServerProxy("http://localhost:8002/") # method 1. 用unicode编码 s = u"美女" print "the variable to transfer is "+ s res_u1 = proxy.printf(s) # method 2. decode to unicode s = "美女" print "the variable to transfer is "+ s res_u2 = proxy.printf(s.decode(‘latin1‘)) assert res_u1 == res_u2 res_gbk = res_u1.encode(‘latin1‘) print res_gbk # 再进一步 def unicode_to_gbk(s): return s.encode(‘latin1‘).decode(‘utf-8‘).encode(‘gbk‘) res = proxy.idx("1,1") # receive unicode a = [unicode_to_gbk(s) for s in res] # transfer unicode->gbk print a[0], a[1]
以上是关于用XMLRPC开服务进行server/client通信的主要内容,如果未能解决你的问题,请参考以下文章