A benefit of the multithreading approach is that the OS handles the thread switches for us, which means we can continue to write our program in a procedural style. Hence we only need to make small adjustments to our server program to make it multithreaded, and thus, capable of handling multiple clients simultaneously.
Create a new file called 1.3-echo_server-multi.py
and add the following code to it:
import threading import tincanchat HOST = tincanchat.HOST PORT = tincanchat.PORT def handle_client(sock, addr): """ Receive one message and echo it back to client, then close socket """ try: msg = tincanchat.recv_msg(sock) # blocks until received # complete message msg = '{}: {}'.format(addr, msg) print(msg) tincanchat.send_msg(sock, msg) # blocks until sent except (ConnectionError, BrokenPipeError): print('Socket error') finally: print('Closed connection to {}'.format(addr)) sock.close() if __name__ == '__main__': listen_sock = tincanchat.create_listen_socket(HOST, PORT) addr = listen_sock.getsockname() print('Listening on {}'.format(addr)) while True: client_sock,addr = listen_sock.accept() # Thread will run function handle_client() autonomously # and concurrently to this while loop thread = threading.Thread(target=handle_client, args=[client_sock, addr], daemon=True) thread.start() print('Connection from {}'.format(addr))
You can see that we've just imported an extra module and modified our main loop to run our handle_client()
function in separate threads, rather than running it in the main thread. For each client that connects, we create a new thread that just runs the handle_client()
function. When the thread blocks on a receive or send, the OS checks the other threads to see if they have come out of a blocking state, and if any have, then it switches to one of them.
Notice that we have set the daemon
argument in the thread constructor call to True
. This will allow the program to exit if we hit ctrl - c without us having to explicitly close all of our threads first.
If you try this echo server with multiple clients, then you'll see that a second client that connects and sends a message will immediately get a response.