用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通信的主要内容,如果未能解决你的问题,请参考以下文章

利用 XMLRpc的 SSRF 漏洞进行内网端口的探测

将 XMLRPC/Web 服务与核心数据集成

dll中的xmlrpc服务器,向自己发送信号?

在 ejabberd 中安装 mod_xmlrpc 后出错

xmlrpc 服务器的问题

PHP xmlrpc 客户端和 Python 2.5 xmlrpc 服务器:不完整的数据和由对等错误重置的连接