=== 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()}")