使用ThreadingMixIn类的特点: 在线程间共享应用的状态,与使用ForkingMixIn类相比避免进程间通信的复杂操作。
代码如下:
1 #! /usr/bin/python 2 3 import os 4 import socket 5 import threading 6 import SocketServer 7 8 SERVER_HOST = ‘localhost‘ 9 SERVER_PORT = 0 10 BUF_SIZE = 1024 11 12 def client(ip, port, message): 13 """A client to test threading mixin server""" 14 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15 sock.connect((ip, port)) 16 try: 17 sock.sendall(message) 18 response = sock.recv(BUF_SIZE) 19 print "Client received: %s" % response 20 finally: 21 sock.close() 22 23 24 class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler): 25 """An example of threaded TCP request handler """ 26 def handle(self): 27 data = self.request.recv(1024) 28 current_thread = threading.current_thread() 29 response = "%s: %s" % (current_thread.name, data) 30 self.request.sendall(response) 31 32 class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): 33 """Nothing add here, inherited everything from parenets""" 34 pass 35 36 if __name__ == ‘__main__‘: 37 #run server 38 server = ThreadedTCPServer((SERVER_HOST, SERVER_PORT), ThreadedTCPRequestHandler) 39 ip, port = server.server_address 40 41 # start a thread with the server, one thread per request 42 server_thread = threading.Thread(target=server.serve_forever) 43 # Exit the server thread when the main thread exits 44 server_thread.daemon = True 45 server_thread.start() 46 print "Server loop running on thread: %s" % server_thread.name 47 48 # run clients 49 client(ip, port, "Hello from client1") 50 client(ip, port, "Hello from client2") 51 client(ip, port, "Hello from client3") 52 53 #server cleanup 54 server.shutdown() 55
注意点1,在写ThreadedTCPRequestHandler类中的方法handle的时候将handle写为了handler,结果在执行程序后,显示服务器返回给客户端的信息为空,原因是handle方法是ThreadedTCPRequestHandler类所继承的BaseRequestHandler类的类方法,由于BaseRequestHandler类的handle方法默认行为是啥也不做,所以要覆写handle方法来处理接受客户端消息,处理客户端请求,如果写为handler则在程序中默认调用了父类BaseRequestHandler的handle方法,但是啥也没做,所以显示服务器返回信息为空。
- RequestHandler.handle()
-
This function must do all the work required to service a request. The default implementation does nothing. Several instance attributes are available to it; the request is available as self.request; the client address as self.client_address; and the server instance as self.server, in case it needs access to per-server information.The type of self.request is different for datagram or stream services. For stream services, self.request is a socket object; for datagram services, self.request is a pair of string and socket. However, this can be hidden by using the request handler subclasses StreamRequestHandler or DatagramRequestHandler, which override the setup() and finish() methods, and provide self.rfile and self.wfile attributes. self.rfile and self.wfile can be read or written, respectively, to get the request data or return data to the client.
注意点2,关于线程对象的setDaemon属性,为True表示服务器线程为后台线程,当没有活动连接到后台线程时,程序执行完毕自动退出,当没有活动的非后台线程活动时,执行完毕程序才会自动退出。对于本代码,具体表现是如果在setDaemon为True的状态,不执行服务器套接字的shutdown(),程序执行完一样会自动退出,而setDaemon为False的状态, 则一定要执行shutdown(),程序才会自动终止。