歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 用XMLRPC開服務進行server/client通信

用XMLRPC開服務進行server/client通信

日期:2017/3/1 9:14:49   编辑:Linux編程

本文講一下如何用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]

Copyright © Linux教程網 All Rights Reserved