
How to do it...
As seen in the previous socket server based on ForkingMixIn, ThreadingMixIn socket server will follow the same coding pattern of an echo server except for a few things. First, our ThreadedTCPServer will inherit from TCPServer and TheadingMixIn. This multi-threaded version will launch a new thread when a client connects to it. Some more details can be found at http://docs.python.org/2/library/socketserver.html.
The request handler class of our socket server, ForkingServerRequestHandler, sends the echo back to the client from a new thread. You can check the thread information here. For the sake of simplicity, we put the client code in a function instead of a class. The client code creates the client socket and sends the message to the server.
Listing 2.2 shows a sample code on the echo socket server using ThreadingMixIn as follows:
#!/usr/bin/env python # Python Network Programming Cookbook, Second Edition -- Chapter - 2 # This program is optimized for Python 3.5.2. # It may run on any other version with/without modifications. # To make it run on Python 2.7.x, needs some changes due to API differences. # begin with replacing "socketserver" with "SocketServer" throughout the program. # See more: http://docs.python.org/2/library/socketserver.html # See more: http://docs.python.org/3/library/socketserver.html import os import socket import threading import socketserver SERVER_HOST = 'localhost' SERVER_PORT = 0 # tells the kernel to pickup a port dynamically BUF_SIZE = 1024 def client(ip, port, message): """ A client to test threading mixin server""" # Connect to the server sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, port)) try: sock.sendall(bytes(message, 'utf-8')) response = sock.recv(BUF_SIZE) print ("Client received: %s" %response) finally: sock.close() class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): """ An example of threaded TCP request handler """ def handle(self): data = self.request.recv(1024) cur_thread = threading.current_thread() response = "%s: %s" %(cur_thread.name, data) self.request.sendall(bytes(response, 'utf-8')) class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): """Nothing to add here, inherited everything necessary from parents""" pass if __name__ == "__main__": # Run server server = ThreadedTCPServer((SERVER_HOST, SERVER_PORT),
ThreadedTCPRequestHandler) ip, port = server.server_address # retrieve ip address # Start a thread with the server -- one thread per request server_thread = threading.Thread(target=server.serve_forever) # Exit the server thread when the main thread exits server_thread.daemon = True server_thread.start() print ("Server loop running on thread: %s" %server_thread.name) # Run clients client(ip, port, "Hello from client 1") client(ip, port, "Hello from client 2") client(ip, port, "Hello from client 3") # Server cleanup server.shutdown()