Think of a server as a business with an office: clients come to it for a service. A server is a program that waits for client connections, receives requests, does the requested work, and may send a reply. A web browser and a web server are one familiar pair. section 10.2 section 10.3
To find the right office, a client needs the server’s IP address and port. The server binds a socket to that address and port and listens. When a client connects, the server gets a separate socket for exchanging messages with that client. The two programs can run on the same computer or on different computers across a network. section 10.3 section 10.4
A pizza-ordering server
A Python server listens at 127.0.0.1:12345. Its accept() call waits for a client; Netcat can connect from another terminal and send an order. For an order of 10, the server replies, “Thank you for ordering 10 pizzas!” The waiting terminal is not necessarily stuck: it is blocked until a connection arrives. section 10.4
# Chapter 10/pizza_server.py
from socket import socket, create_server
BUFFER_SIZE = 1024 #1
ADDRESS = ("127.0.0.1", 12345) #2
class Server:
def __init__(self) -> None:
try:
print(f"Starting up at: {ADDRESS}")
self.server_socket: socket = create_server(ADDRESS) #3
except OSError:
self.server_socket.close()
print("\nServer stopped.")
def accept(self) -> socket:
conn, client_address = self.server_socket.accept() #4
print(f"Connected to {client_address}")
return conn
def serve(self, conn: socket) -> None:
try:
while True:
data = conn.recv(BUFFER_SIZE) #5
if not data: #5
break #5
try:
order = int(data.decode())
response = f"Thank you for ordering {order} pizzas!\n"
except ValueError:
response = "Wrong number of pizzas, please try again\n"
print(f"Sending message to {conn.getpeername()}")
conn.send(response.encode()) #6
finally:
print(f"Connection with {conn.getpeername()} has been closed")
conn.close() #7
def start(self) -> None:
print("Server listening for incoming connections")
try: #8
while True: #8
conn = self.accept() #8
self.serve(conn) #8
finally: #8
self.server_socket.close() #8
print("\nServer stopped.") #8
if __name__ == "__main__":
server = Server()
server.start()
Follow the pizza server’s create_server(), accept(), and recv() calls to see how listening becomes a client conversation. section 10.4
That simple server has a limit: while one client occupies it, another waits. Try leaving the first client connected and opening a second. Serving many clients promptly calls for a concurrent approach; merely listening on a port does not provide one. section 10.5
A server can also coordinate workers rather than answer customer orders. In a word-count application, the server communicates with worker processes and asks a central scheduler for their next map or reduce tasks. The service is still organized around connections and messages, but the work is distributed among workers. section 13.14










