Imagine ordering pizza by calling a shop: you need the right address, and someone must be ready to answer. A network socket is an operating-system endpoint that lets a process exchange data with another process over a network. It is a two-way message-passing channel, rather than a file used for communication. section 10.3 section 5.6
A socket uses an IP address and a port. The IP address identifies the host, much like a street address identifies a house. Ports let multiple server applications on that host receive traffic intended for them. A network socket resembles a UNIX domain socket, but carries messages over a network. The network may be local, logical, or connected to the internet. section 10.3
TCP/IP sockets establish a connection before the two processes exchange information, then maintain it during their conversation. To receive clients, a server binds a socket to an IP address and port and listens. Its accept() call waits for a connection; when one arrives, it returns a separate socket for communicating with that client. section 10.3 section 10.4
A pizza-ordering service
A Python server listens at 127.0.0.1:12345, an address on the local computer. A client can connect with Netcat and send 10; the service replies, “Thank you for ordering 10 pizzas!” If the server appears to pause at accept(), it is waiting for a client, not necessarily stuck. 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()
The Python server listing shows create_server() binding the address, accept() obtaining a client connection, and recv() reading from it. section 10.4
