Welcome, guest | Sign In | My Account | Store | Cart

This recipe demonstrates the creation of a simple XML-RPC server using the SimpleXMLRPCServer class. It requires either Python 2.2 or later or the XML-RPC package from PythonWare (http://www.pythonware.com/products/xmlrpc/index.htm) to run.

Python, 37 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Server code

import SimpleXMLRPCServer

class StringFunctions:
    def __init__(self):
        # Make all of the Python string functions available through
        # python_string.func_name
        import string
        self.python_string = string

    def _privateFunction(self):
        # This function cannot be called through XML-RPC because it
        # starts with an '_'
        pass
    
    def chop_in_half(self, astr):
        return astr[:len(astr)/2]

    def repeat(self, astr, times):
        return astr * times
    
server = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 8000))
server.register_instance(StringFunctions())
server.register_function(lambda astr: '_' + astr, '_string')
server.serve_forever()

# Client code

import xmlrpclib

server = xmlrpclib.Server('http://localhost:8000')
print server.chop_in_half('I am a confidant guy')
print server.repeat('Repetition is the key to learning!\n', 5)
print server._string('<= underscore')
print server.python_string.join(['I', 'like it!'], " don't ")
print server._privateFunction() # Will throw an exception

SimpleXMLRPCServer is a simple class that listens for HTTP requests, on a specified port, and dispatches any XML-RPC calls to either a registered instance or a registered function. The example above demonstates both usages.

Registering functions (as opposed to an instance) is necessary if you want to give your functions names beginning with '_' or containing characters not allowed in Python identifiers (Unicode characters, plus signs, etc.)

Note that dotted names (i.e. python_string.join) are correctly resolved for registered instances.

6 comments

Duncan Gough 17 years, 5 months ago  # | flag

Threaded example. This isn't my code, I found it when I wanted to run an XMLRPC server in a separate thread:

class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer):
        pass

if __name__ == "__main__":
        server = SimpleThreadedXMLRPCServer(("localhost", 8001))
        server.register_instance(MyXMLRPCObject()) # register your distant Object here
        server.serve_forever()

More here:

http://www.codecomments.com/Python/message190478.html

http://www.python.org/doc/2.3.3/lib/module-SocketServer.html

A.M. Kuchling 16 years, 10 months ago  # | flag

Forking XML-RPC server. Similarly, you can invoke each XML-RPC method in a single process with code like this:

import SocketServer
import SimpleXMLRPCServer

class ForkingXMLRPCServer (SocketServer.ForkingMixIn,
                           SimpleXMLRPCServer.SimpleXMLRPCServer):
    pass

server = ForkingXMLRPCServer(("localhost", 8000))
# Register functions here...
server.serve_forever()

If using this code, remember that the methods can't rely on any shared global state, for example such as a dictionary used as a cache, because each method is run in a subprocess that does its work and then exits. Any changes to global variables or object attributes in the method won't be visible to the parent process.

KAMOSAWA Masao 15 years, 7 months ago  # | flag

2.4 doesn't allow dotted notation of functions. In this server code, __init__ has

    import string
    self.python_string = string

lines and the client code has the

print server.python_string.join(['I', 'like it!'], " don't ")

line. These codes are intended to use the dotted notation of function that Python 2.4's xmlrpclib disallows to use in default so the client code raise an exception when the line is executed. You can choise from some options to make the client code line to work. they are: ・assign string functions FUNCNAME to self.python_string.FUNCNAME one bye one or by looping names of string functions. ・change the server code: server.register_instance(StringFunctions()) to: server.register_instance(StringFunctions(), allow_dotted_names = True) allows dotted notation of the function.

Thomas Herchenroeder 14 years, 4 months ago  # | flag

Error Message. This is just to confirm the previous post, and add the exception error message (so people like me find this comment faster through searches) if you use the recipe literally :

xmlrpclib.Fault: &lt;Fault 1: '&lt;type \'exceptions.Exception\'&gt;:method "python_string.join" is not supported'&gt;

=Thomas

Gal Aviel 14 years, 4 months ago  # | flag

compression. (Disclaimer : I'm not a python expert in any way, just sharing...)

xmlrpc is great, easy, dynamic but is not effecient as binary methods (see "The Python Web services developer: Messaging technologies compared" at http://www.ibm.com/developerworks/library/ws-pyth9/).

For example, it can take minutes to transfer 100MB of data between client and server.

Therefore, I added compression, using http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/355486.

This shortened the transfer time to 15 seconds. Example server function (returns an arbitrary chunk of bytes, possibly with random values):

from array import array
from random import randint
import zlib, base64

    def get_data(self, default_byte_value=0x00,num_bytes=1024,use_rand=False):
        data = array('B', [default_byte_value] * num_bytes )
        if ( use_rand ):
            for i in range(num_bytes):
                data[i] = randint(0, 255)
        data,csum = asciiCompress(buffer(data))
        return data

Example client side (request a 1MB chunk of bytes using 0x11 as default value for each byte (non random)).

data = server.get_data(0x11,1 * 10**6,False)
data,csum = asciiDecompress(data)
arr = array('B',data)

Note that we originate from a python array at the server and end up with an array at the client.

Just my 2 cents :)

uzmanajmal 13 years, 2 months ago  # | flag

How do i set header while calling method at server side? I want to call a function named system.auth at server side while setting the header via:

import httplib httplib.HTTPConnection.putheader("AUTHORIZATION", "Basic %s"%encodestring("%s:%s" % (ustring,text_ucert)))