Blocking socket server
To illustrate the difference with a blocking socket approach, we'll create a simple blocking TCP server and a corresponding client. This server will handle one connection at a time in a blocking manner, meaning it will wait (or block) on I/O operations like accepting new connections or receiving data.
import socket HOST = '127.0.0.1' # Standard loopback interface address (localhost) PORT = 65432 # Port to listen on (non-privileged ports are > 1023) # Create a socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket: server_socket.bind((HOST, PORT)) server_socket.listen() print(f"Server is listening on {HOST}:{PORT}") while True: # Accept a new connection conn, addr = server_socket.accept() with conn: print(f"Connected by {addr}") while True: data = conn.recv(1024) if not data: break # No more data from client, close connection print(f"Received {data.decode()} from {addr}") response = "This is a response from the server.".encode() conn.sendall(response)
Blocking client
import socket HOST = '127.0.0.1' # The server's hostname or IP address PORT = 65432 # The port used by the server # Create a socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) print("Connected to the server") # Send data message = 'Hello, server'.encode() s.sendall(message) print("Message sent to the server") # Wait for a response data = s.recv(1024) print("Received response from the server") print(f"Received: {data.decode()}")
Non-blocking server
Creating a non-blocking TCP socket server in Python involves setting up a socket to listen for connections without blocking the main execution thread of the program. Below is a simple example of a non-blocking TCP server that accepts multiple client connections and handles them asynchronously. This server uses the select method, which is a way to check for I/O readiness on sockets, making it possible to manage multiple connections without blocking on any single one.
import socket import select HOST = '127.0.0.1' # Standard loopback interface address (localhost) PORT = 65432 # Port to listen on (non-privileged ports are > 1023) # Create a socket server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Bind the socket to the address and port server_socket.bind((HOST, PORT)) # Listen for incoming connections server_socket.listen() print(f"Listening on {HOST}:{PORT}") # Set the server socket to non-blocking mode server_socket.setblocking(0) # Keep track of input sockets inputs = [server_socket] outputs = [] while inputs: # Wait for at least one of the sockets to be ready for processing readable, writable, exceptional = select.select(inputs, outputs, inputs) for s in readable: if s is server_socket: # Accept new connection connection, client_address = s.accept() print(f"New connection from {client_address}") connection.setblocking(0) inputs.append(connection) else: data = s.recv(1024) if data: # A readable client socket has data print(f"Received {data} from {s.getpeername()}") # Add output channel for response if s not in outputs: outputs.append(s) else: # Interpret empty result as closed connection print(f"Closing {client_address}") if s in outputs: outputs.remove(s) inputs.remove(s) s.close() for s in writable: response = b'This is a response from the server.' s.send(response) # Once response has been sent, we don't need to write anymore outputs.remove(s) for s in exceptional: print(f"Handling exceptional condition for {s.getpeername()}") # Stop listening for input on the connection inputs.remove(s) if s in outputs: outputs.remove(s) s.close()
Non-blocking client
To test the non-blocking TCP server, you can create a simple client that connects to the server, sends a message, and then waits to receive a response. Below is an example of a basic TCP client in Python that interacts with our non-blocking server.
import socket HOST = '127.0.0.1' # The server's hostname or IP address PORT = 65432 # The port used by the server # Create a socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: # Connect to the server s.connect((HOST, PORT)) print("Connected to server") # Send data message = 'Hello, server'.encode() s.sendall(message) print("Message sent to server") # Wait for a response data = s.recv(1024) print("Received response from server") print(f"Received: {data.decode()}")