使用多路复用套接字I/O提升性能之——ForkingMixIn 《Python网络编程攻略》

来源:互联网 发布:软件生存周期模型 编辑:程序博客网 时间:2024/06/06 00:23

与前一例不同,本次考虑多个客户端连接服务器的情况,且可以异步通信。

服务器不需要在阻塞模式中处理客户发出的请求,而是单独处理每个请求。如果某个客户端接受或处理数据花了很长时间,服务器无需等待处理完成,即可使用另外的线程和其他客户端进行通信。

实现方法

  1. SocketServer模块:利用SocketServer模块提供的类可以直接实现TCP、UDP及其他协议服务器。
  2. ForkingMixIn类,用于异步处理客户端。
  3. 我们创建ForkingServer类,继承TCPServer和ForkingMixIn类。继承TCPServer可以省去手动创建服务器操作,如创建套接字、绑定地址和监听连接等;继承ForkingMinIn用于异步处理。
  4. ForkingServer类还要创建一个请求处理程序ForkingServerRequestHandler(继承自SocketServer库中的BaseRequestHandler类),说明如何处理客户端请求。
  5. 客户端ForkingClient使用面向对象的方式编写。

代码 2_1_forking_mixin_socket_server.py

'''Created on 2017-2-28@author: lenovo'''import osimport socketimport threadingimport SocketServerSERVER_HOST = 'localhost'SERVER_PORT = 0 # Tells the kernel to pick up a port dynamicallyBUF_SIZE = 1024ECHO_MSG = 'Hello echo server!'class ForkingClient():    """ A client to test forking server"""    def __init__(self,ip,port):        # Create a socket        self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)        self.sock.connect((ip,port))    def run(self):        """Client playing with the server"""        #send the data to server        current_process_id = os.getpid()        print 'PID %s Sending echo message to the server : "%s"' %(current_process_id,ECHO_MSG)        sent_data_length = self.sock.send(ECHO_MSG)        print "Sent: %d characters, so far..." %sent_data_length        # Display server response        response = self.sock.recv(BUF_SIZE)        print "PID %s received: %s" %(current_process_id,response[5:])    def shutdown(self):        self.sock.close()class ForkingServerRequestHandler(SocketServer.BaseRequestHandler):    def handle(self):        # Send the echo back to the client        data = self.request.recv(BUF_SIZE)        current_process_id = os.getpid()        response = '%s: %s' % (current_process_id,data)        print "Server sending response [current_process_id: data] = [%s]" %response        self.request.send(response)        returnclass ForkingServer(SocketServer.ForkingMixIn,SocketServer.TCPServer,):    """Nothing to add here, inherited everything necessary form parents."""    passdef main():    #Launch the server    server = ForkingServer((SERVER_HOST,SERVER_PORT),ForkingServerRequestHandler)    ip,port = server.server_address #Retrive the port number    server_thread = threading.Thread(target=server.serve_forever)    server_thread.setDaemon(True)    server_thread.start()    print 'Server loop running PID: %s' %os.getpid()    #Launch the client    client1 = ForkingClient(ip,port)    client1.run()    client2 = ForkingClient(ip,port)    client2.run()    #clean them up    server.shutdown()    client1.shutdown()    client2.shutdown()    server.socket.close()if __name__ == '__main__':    main()

运行结果

xx@ubuntu:~$ python 2_1_forking_mixin_socket_server.py Server loop running PID: 2545PID 2545 Sending echo message to the server : "Hello echo server!"Sent: 18 characters, so far...Server sending response [current_process_id: data] = [2547: Hello echo server!]PID 2545 received:  Hello echo server!PID 2545 Sending echo message to the server : "Hello echo server!"Sent: 18 characters, so far...Server sending response [current_process_id: data] = [2548: Hello echo server!]PID 2545 received:  Hello echo server!xx@ubuntu:~$

原理分析

主线程中创建了一个ForkingServer实例,作为守护进程在后台运行,然后再创建两个客户端与服务器交互。

不难发现,服务器每次响应请求的进程是不同,一个是2547,一个是2548,可见服务器对每个客户端请求生成了不同的进程去去处理。

0 0
原创粉丝点击