部分ssrpc.py代码分析 -- 服务端:
1 #!/usr/bin/python3
2
3 from xmlrpc.client import Fault, dumps, loads
4 import sys
5 from socketserver import ForkingMixIn
6 from xmlrpc.server import SimpleXMLRPCServer
7
8 class VerboseFaultXMLRPCServer(SimpleXMLRPCServer):
9 def _marshaled_dispatch(self, data, dispatch_method = None, path = None):
10 """Dispatches an XML-RPC method from marshalled (XML) data.
11
12 XML-RPC methods are dispatched from the marshalled (XML) data
13 using the _dispatch method and the result is returned as
14 marshalled data. For backwards compatibility, a dispatch
15 function can be provided as an argument (see comment in
16 SimpleXMLRPCRequestHandler.do_POST) but overriding the
17 existing method through subclassing is the preferred means
18 of changing method dispatch behavior.
19 """
20
21 try:
22 params, method = loads(data)
23
24 # generate response
25 if dispatch_method is not None:
26 response = dispatch_method(method, params)
27 else:
28 response = self._dispatch(method, params)
29 # wrap response in a singleton tuple
30 response = (response,)
31 response = dumps(response, methodresponse=1,
32 allow_none=self.allow_none, encoding=self.encoding)
33 except Fault as fault:
34 response = dumps(fault, allow_none=self.allow_none,
35 encoding=self.encoding)
36 except:
37 # report exception back to server
38 exc_type, exc_value, exc_tb = sys.exc_info()
39 while exc_tb.tb_next is not None:
40 exc_tb = exc_tb.tb_next # find last frame of the traceback
41 lineno = exc_tb.tb_lineno
42 code = exc_tb.tb_frame.f_code
43 filename = code.co_filename
44 name = code.co_name
45 response = dumps(
46 Fault(1, "%s:%s FILENAME: %s LINE: %s NAME: %s" % (
47 exc_type, exc_value, filename, lineno, name)),
48 encoding=self.encoding, allow_none=self.allow_none,
49 )
50
51 return response.encode(self.encoding)
52
53 # One process per request
54 class ForkingXMLRPCServer(ForkingMixIn, VerboseFaultXMLRPCServer):
55 max_children = 500 # default is 40
56
57 server = ForkingXMLRPCServer(("", 8889), allow_none=True)
58
59 # Register functions here
60
61 from ssapi.disk.sas import sasdiskinfo
62 from ssapi.disk.ledctl import ledctl_set
63 from ssapi.zfs.zpoollist import zpoollist
64 from ssapi.zfs.zpoolstatus import zpoolstatus
65 from ssapi.zfs.zpoolcreate import zpoolcreate
66
67 funcs = [
68 sasdiskinfo,
69 ledctl_set,
70 zpoollist,
71 zpoolstatus,
72 zpoolcreate,
73 ]
74
75 for i in funcs:
76 server.register_function(i)
77
78 # Start service
79 server.serve_forever()
正如上篇文章所述,SimpleXMLRPCServer是一个单线程的服务器,所以这里支持多进程的方式如下:
1.定义VerboseFaultXMLRPCServer类,继承于SimpleXMLRPCServer
2.定义一个新类:ForkingXMLRPCServer(ForkingMixIn, VerboseFaultXMLRPCServer),其中ForkingMixIn是从socketserver中导入
3.调用新类创建server实体,server = ForkingXMLRPCServer(("", 8889), allow_none=True),则支持多进程
/usr/lib/python3.2/xmlrpc/server.py 中SimpleXMLRPCServer源代码:
1 class SimpleXMLRPCServer(socketserver.TCPServer,
2 SimpleXMLRPCDispatcher):
3 """Simple XML-RPC server.
4
5 Simple XML-RPC server that allows functions and a single instance
6 to be installed to handle requests. The default implementation
7 attempts to dispatch XML-RPC calls to the functions or instance
8 installed in the server. Override the _dispatch method inherited
9 from SimpleXMLRPCDispatcher to change this behavior.
10 """
11
12 allow_reuse_address = True
13
14 # Warning: this is for debugging purposes only! Never set this to True in
15 # production code, as will be sending out sensitive information (exception
16 # and stack trace details) when exceptions are raised inside
17 # SimpleXMLRPCRequestHandler.do_POST
18 _send_traceback_header = False
19
20 def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler,
21 logRequests=True, allow_none=False, encoding=None, bind_and_activate=True):
22 self.logRequests = logRequests
23
24 SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
25 socketserver.TCPServer.__init__(self, addr, requestHandler, bind_and_activate)
26
27 # [Bug #1222790] If possible, set close-on-exec flag; if a
28 # method spawns a subprocess, the subprocess shouldn't have
29 # the listening socket open.
30 if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
31 flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
32 flags |= fcntl.FD_CLOEXEC
33 fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)