- xmlrpc Library
- Simple server side
- Simple client
- Multithreaded access
- File upload & Download
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.
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.
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.
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.
# _*_ 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.
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:
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