标签:
第二章主要在上一章的基础上介绍了以下内容:
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上定义的套接字,在其他平台上不能使用。
图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()
《Python Network Programming Cookbook》读书笔记2---复用socket I/O 实现更好的性能
标签:
原文地址:http://www.cnblogs.com/weixinbupt/p/4709566.html