Python网络编程(2)---复用socket I/O 实现更好的性能

  第二章主要在上一章的基础上介绍了以下内容:

    1. ForkingMixIn

    2. ThreadingMixIn

    3. select.select

    4. select.epoll

    5. Diesel库

ForkingMixIn 和 ThreadingMixIn属于socketserver(python2是SocketServer)模块,该模块能够简化编写web服务器的工作。其包含四种基本的服务器class:

  TCPServer 使用TCP协议,在服务器和客户端之间建立持续的连续,安全;

  UDPServer 使用UDP协议,采用数据包的方法在服务器和客户端之间传递数据,有丢失包的可能,但是传输速度很快;

  UnixStreamServer和UnixDatagramServer 比较少使用, 分别与TCPServer、UDPServer相似,但是基于Unix上定义的套接字,在其他平台上不能使用。

Python网络编程(2)---复用socket I/O 实现更好的性能_第1张图片

图1. Servers的继承关系

以上四种类都是同步的,即下一个请求开始前,上一个请求必须完成。显然,他们并不适用于当请求需要较长处理时间的情况。为每个请求创建单独的进程或线程的方式可以解决这个问题,即实现服务器和客户端的异步通信,为此socketserver模块添加了ForkingMixIn和ThreadingMixIn两个类。

  为了创建一个服务,首先通过继承BaseRequestHandler类并重写其handler()方法得到一个句柄类,它将用来处理到达服务器的请求;

class ForkingServerRequestHandler(SocketServer.BaseRequestHandler):

然后以服务器地址和上一步得到的句柄实例化前面继承自ForkingMixIn/ThreadingMixIn和TCPServer/UDPServer/UnixStreamServer/UnixDatagramServer的server,

class ForkingServer(SocketServer.ForkingMixIn, SocketServer.TCPServer,):
    pass

server = ForkingServer((SERVER_HOST, SERVER_PORT), ForkingServerRequestHandler)

注意:ForkingMixIn必须写在TCPServer前面,因为它重载了TCPServer类的方法。

最后,调用handler_request()或者server_forever()方法来开始处理请求。

server_thread = threading.Thread(target=server.serve_forever)

  值得注意的是,如果server类继承自ThreadingMixIn,则需要明确指定遇到异常停止时的处理方法,ThreadingMixIn类定义了daemon_threads方法,其指定了服务器是否需要等待直到所有线程终止,默认为False。

server_thread.setDaemon(True)

下面是一个简单的例子:

import os
   import socket
   import threading
   import SocketServer
   SERVER_HOST = 'localhost'
   SERVER_PORT = 0 # tells the kernel to pick up a port dynamically
   BUF_SIZE = 1024
   ECHO_MSG = 'Hello echo server!'
   class ForkedClient():
       """ A client to test forking server"""
       def __init__(self, ip, port):
           # Create a socket
           self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
           # Connect to the server
            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):
           """ Cleanup the client socket """
           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)
return
   class ForkingServer(SocketServer.ForkingMixIn,
                       SocketServer.TCPServer,
                       ):
       """Nothing to add here, inherited everything necessary from
   parents"""
       pass
   def main():
       # Launch the server
       server = ForkingServer((SERVER_HOST, SERVER_PORT),
   ForkingServerRequestHandler)
       ip, port = server.server_address # Retrieve the port number
       server_thread = threading.Thread(target=server.serve_forever)
       server_thread.setDaemon(True) # don't hang on exit
       server_thread.start()
       print 'Server loop running PID: %s' %os.getpid()
       # Launch the client(s)
       client1 =  ForkedClient(ip, port)
       client1.run()
       client2 =  ForkedClient(ip, port)
       client2.run()
       # Clean them up
       server.shutdown()
       client1.shutdown()
       client2.shutdown()
       server.socket.close()
   if __name__ == '__main__':
       main()

  

转载于:https://www.cnblogs.com/weixinbupt/p/4709566.html

你可能感兴趣的:(Python网络编程(2)---复用socket I/O 实现更好的性能)