Python 3 simply uses xmlrpc to implement RPC

catalogue

  • RPC
  • xmlrpc Library
  • Simple server side
  • Simple client
  • Multithreaded access
  • File upload & Download

RPC

Let's talk about what RPC is first. RPC (Remote Procedure Call) - Remote Procedure Call is a protocol that requests services from remote computer programs through the network without understanding the underlying network technology. RPC Protocol assumes the existence of some transmission protocols, such as TCP or UDP, to carry information data between communication programs. In the OSI network communication model, RPC spans the transport layer and application layer. RPC makes it easier to develop applications including network distributed multiprogramming.

RPC adopts client / server mode. The requester is a client, and the service provider is a server. First, the client invokes the process to send a call information with process parameters to the service process, and then waits for the response information. On the server side, the process stays asleep until the call information arrives. When a calling message arrives, the server obtains the process parameters, calculates the result, sends the reply information, and then waits for the next call information. Finally, the client calls the process to receive the reply information, gets the process result, and then calls the execution to proceed.

To put it bluntly, it is a way to call the function interface remotely. A contract (function interface) is agreed between the client and the server, and then the server has been waiting for the call of the client. It's a bit like an ordinary WEB network request, but this method is very lightweight and does not involve HTTP. You can see that the implementation is very simple later.

As mentioned above, one purpose is to call each other between multiple servers, and the other is to support this method between different programming languages. For example, Python has built-in support for it and does not need to install any additional libraries, so you can call each other directly between servers in multiple languages. It is very simple.

xmlrpc Library

In Python 2 (most of the information on Python 2 using RPC on the Internet), the server needs to use the simplexmlpcserver library and the client needs to use the ServerProxy library. In Python 3, the two are integrated into the same database xmlrpc Library It is divided into two parts: xmlrpc.server and xmlrpc.client. Therefore, if you use it under Python 3, you need to import this library.

Simple server side

What does the server need to do?

Like a web request, we need to determine the url and port number for the client to access and the method implementation for the client to call. Finally, we need to keep our server waiting to be accessed:

# _*_ coding:utf-8 _*_

from xmlrpc.server import SimpleXMLRPCServer

# Call function
def respon_string(str):
    return "get string:%s"%str


if __name__ == '__main__':
    server = SimpleXMLRPCServer(('localhost', 8888)) # initialization
    server.register_function(respon_string, "get_string") # Register function
    print ("Listening for Client")
    server.serve_forever() # Keep waiting for call

As you can see, the above points are implemented in the code. register_function is used to register a function for calling. The first parameter is the method name implemented by itself, and the second parameter is the method name called by the client.

Simple client

The client has less to do: initialize a server object based on url and port number, and then call the required method.

# _*_ coding:utf-8 _*_

from xmlrpc.client import ServerProxy

if __name__ == '__main__':
    server = ServerProxy("http://localhost:8888 ") # initialize the server
    print (server.get_string("cloudox")) # Call the function and pass parameters

At this time, we use two terminals to run the server and client, and we can see the effect:

The server starts and keeps listening

The client remotely called multiple times

As can be seen from the figure, each time the server is accessed, the access source will be printed. After the client accesses, the specific implementation of the function running on the server will be called remotely.

Multithreaded access

The above method can only be accessed by a single thread, but in most cases, it needs to support multithreading. How to deal with it? Very simple, just change the server:

# _*_ coding:utf-8 _*_

from xmlrpc.server import SimpleXMLRPCServer
from socketserver import ThreadingMixIn


class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    pass

# Call function 1
def respon_string(str):
    return "get string:%s"%str

# Call function 2
def add(x, y):
    return x + y


if __name__ == '__main__':
    server = ThreadXMLRPCServer(('localhost', 8888)) # initialization
    server.register_function(respon_string, "get_string") # Register function 1
    server.register_function(add, 'add') # Register function 2
    print ("Listening for Client")
    server.serve_forever() # Keep waiting for call

In the code, we no longer use simplexmlrpserver to initialize the server, but a custom class, which inherits from two base classes. ThreadingMixIn enables it to support multithreading, and the other operation methods are the same as normal. In addition, we have added a function that accepts two parameters and calculates and. We can see that we register the function regardless of the number of parameters Always write only the function name.

The client code is as follows:

# _*_ coding:utf-8 _*_

from xmlrpc.client import ServerProxy

if __name__ == '__main__':
    server = ServerProxy("http://localhost:8888 ") # initialize the server
    print (server.get_string("cloudox")) # Call function 1 and pass parameters
    print (server.add(8, 8)) # Call function 2 and pass parameters

The result of the client calling the two functions

The effect of multithreading cannot be shown here, but the calls to both functions succeeded.

File upload & Download

In addition to transmitting parameters, RPC can also transfer files between the client and the server - the client can download files from the server or upload files to the server.

The xmlrpc.client.Binary library is used to transfer files. If you want to realize the function of downloading files from the server, the server side also needs to import this library, even if it nominally belongs to the client library.

The basic steps for transferring files are:

  • Open a file with open (if not, it will be created) to determine whether it is read permission or write permission;
  • At the file sending end, the file is transmitted by calling xmlrpc.client.Binary, and the receiving end obtains the content through the value. data (see the code for details);
  • Close the file.

The server:

# _*_ coding:utf-8 _*_

from xmlrpc.server import SimpleXMLRPCServer
from socketserver import ThreadingMixIn
import xmlrpc.client


class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    pass


# Files for clients to download
def image_get():
    handle = open("boy.jpg", 'rb')
    return xmlrpc.client.Binary(handle.read())


# For client to upload files
def image_put(data):
    handle = open("get_girl.jpg", 'wb')
    handle.write(data.data)
    handle.close()


if __name__ == '__main__':
    server = ThreadXMLRPCServer(('localhost', 8888), allow_none=True) # initialization
    server.register_function(image_put, 'image_put')
    server.register_function(image_get, 'image_get')
    print ("Listening for Client")
    server.serve_forever() # Keep waiting for call

The code initializes the server with more than one parameter allow_none=True. It is allowed not to return parameters to the client, because the file upload functions do not return values. If this parameter is not set, an error will be reported. In fact, a value should also be returned to tell the client whether the upload is successful.

It can be seen from the file upload code that data.data is written, and only data will report an error, because in fact, Binary.data is to be written, which can also be seen when the following client code downloads the file.

client:

from xmlrpc.client import ServerProxy
import xmlrpc.client

if __name__ == '__main__':
    server = ServerProxy("http://localhost:8888", allow_none=True)
    # Upload file
    put_handle = open("girl.jpg", 'rb')
    server.image_put(xmlrpc.client.Binary(put_handle.read()))
    put_handle.close()
    # Download File
    get_handle = open("get_boy.jpg", 'wb')
    get_handle.write(server.image_get().data)
    get_handle.close()

You can see that when downloading a file, you write the obtained return value. data instead of the return value itself. You must pay attention to this.

You can check the code directory and find that the file transfer (upload & download are all in one directory) is successful:

junction

The above is how Python 3 uses xmlrpc. It can be seen that it is indeed very simple to realize remote call. Although it is all on one machine, it only needs to change the IP to support remote call. This is much simpler than building a WEB background server. If you only want to realize simple function calls, using RPC will save a lot of effort.

Here is my code: https://github.com/Cloudox/PythonRPCStudy

Posted by Ace_Online on Tue, 23 Nov 2021 00:28:32 -0800