2017.07.12 Python network programming using multiplexed socket I/O

1. Before starting this chapter, you need to understand the difference between synchronous and asynchronous, blocking and non-blocking:

“Blocking” and “non-blocking” and “synchronous” and “asynchronous” cannot be simply understood literally, providing an answer from the perspective of a distributed system. 1. Synchronous and asynchronous
Synchronous and asynchronous focus on the message communication mechanism (synchronous communication/ asynchronous communication)
The so-called synchronization means that when a *call* is issued, the *call* will not return until the result is obtained. But once the call returns, you get the return value.
In other words, it is the *caller* who actively waits for the result of this *call*.

Asynchronous is the opposite. After *call* is issued, the call returns directly, so no result is returned. In other words, when an asynchronous procedure call is issued, the caller does not get the result immediately. Instead, after the *call* is issued, the *callee* notifies the caller through status, notification, or handles the call through a callback function.

Typical asynchronous programming models such as Node.js

To give a popular example:
You call and ask the bookstore owner if he has the book “Distributed System”. If it is a synchronous communication mechanism, the bookstore owner will say, wait a moment, “I will check”, and then start to check and check, and wait until it is finished ( It may be 5 seconds, or it may be a day) tell you the result (return the result).
As for the asynchronous communication mechanism, the bookstore owner directly tells you that I will check it, and after checking it, I will call you, and then hang up directly (without returning the result). Then check it out, and he will take the initiative to call you. Here the boss calls back by “calling back”.

2. Blocking and non-blocking
Blocking and non-blocking focus on the status of the program while waiting for the call result (message,return value).

A blocking call means that the current thread will be suspended before the result of the call is returned. The calling thread will not return until it has the result.
A non-blocking call means that the call will not block the current thread until the result cannot be obtained immediately.

Or the above example,
You call the bookstore owner to ask if he has the book “Distributed System”. If you call it in a blocking manner, you will “hang up” yourself until you get the result of whether the book is available. If it is a non-blocking call, You don’t care whether the boss told you or not, you go to play first, of course, you have to occasionally check in a few minutes to see if the boss has returned the result.
Here blocking and non-blocking have nothing to do with whether it is synchronous or asynchronous. It has nothing to do with how the boss answers your results.

2. Use ForkingMixIn in the socket server program:

# -*- coding: UTF-8 -*-<br># Write an asynchronous Python socket server program, the server cannot block when processing the request sent by the client,<br># So find a mechanism to handle each client individually,<br># The SocketServer module in Python2.7 provides two utility classes: ForkingMixIn and ThreadingMixIn,<br># ForkingMixIn will fork a new process for each client request<br># !usr/bin/env python<br>#Python Network Programming Cookbook --Chapter-1<br># This program is optimized for Python 2.7<br># It may run on any other version with/without modifications<br><br>import os<br>import socket<br>import threading<br>import SocketServer<br><br>SERVER_HOST='localhost'<br>SERVER_PORT=0<br>BUF_SIZE=1024<br>ECHO_MSG='Hello echo server'<br><br>class ForkingClient():<br>    """A forKing service client test"""<br>    def __init__(self, ip, port):<br>        self.sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)<br>        self.sock.connect((ip,port))<br><br>    def run(self):<br>        """Client and server interaction"""<br>        current_process_id = os. getpid()<br>        print 'PID%s send an echo message to the server:"%s"' %(current_process_id,ECHO_MSG)<br><br>        sent_data_length=self.sock.send(ECHO_MSG)<br>        print "Sent:%d characters , so far....." %sent_data_length<br><br>        response=self.sock.recv(BUF_SIZE)<br>        print "PID%s received: %s" %(current_process_id,response[5:])<br><br>    def shutdown(self):<br>        """Clear client socket"""<br>        self. sock. close()<br><br>class ForkingServerRequestHandler(SocketServer. BaseRequestHandler):<br>    def handle(self):<br>        data=self.request.recv(BUF_SIZE)<br>        current_process_id = os. getppid()<br>        response='%s :%s' %(current_process_id,data)<br>        print "The server sent a response [current process ID: data]=[%s]" %response<br>        self.request.send(response)<br>        return<br><br>class ForkingServer(SocketServer. ForkingMixIn,SocketServer.TCPServer):<br>    """There is nothing to add here, inherit the necessary attributes from the parent class"""<br>    pass<br><br>def main():<br>    server=ForkingServer((SERVER_HOST,SERVER_PORT),ForkingServerRequestHandler)<br>    ip,port=server.server_address<br>    server_thread=threading.Thread(target=server.serve_forever)<br>    server_thread. setDaemon(True)<br>    server_thread. start()<br>    print 'Server loop running PID: %s' %os.getpid()<br><br>    client1=ForkingClient(ip,port)<br>    client1. run()<br><br>    client2=ForkingClient(ip,port)<br>    client2. run()<br><br>    server. shutdown()<br>    client1. shutdown()<br>    client2. shutdown()<br>    server.socket.close()<br><br><br>if __name__=='__main__':<br>    main()<br><br><br>The program consists of 3 parts:<br>
     
      <img src="//i2.wp.com/img-blog.csdnimg.cn/img_convert/54b1c49ac57b1b6f004d33f081d99527.png" alt="" style="outline: none;">
     <br>Most of the work required to create a SocketServer is to define a request handler class.<br>It is a subclass of the BaseRequestHandler class in the SocktServer module, and each request handler object handles a client's request when the client connects to the server.<br>This is implemented in the handle method of the request handler.<br>

Whenever a connection is made to this server, the TCPServer class will pass the correct variables to create a new RequestHandler and call the handle method to handle the request.

Here is the server class and main method:

process_request will inherit from ThreadingMixIn or ForkingMixIn, create a new thread for each request, and then call finish_request by the thread<br>operation result:<br>
      
       <img src="//i2.wp.com/img-blog.csdnimg.cn/img_convert/e8e00c293c134c1f32aa76dc8686ccef.png" alt="" style="outline: none;">