liveBook · Manning

Server socket

As explained in Grokking Concurrency

A server socket is a socket configured to listen for and accept incoming client connections.

Think of a server socket as a front desk for a network service: it binds to an address and port, listens for visitors, and waits for clients to arrive. Calling accept() pauses the server until a connection appears. It then returns a new socket for communicating with that client, while the listening socket remains ready for others. section 10.4

A basic server socket follows this sequence:

  • Bind the socket to an address such as 127.0.0.1 and a port such as 12345. section 10.4
  • Listen for incoming client connections. section 10.4
  • Call accept() and receive a connected socket plus the client address. section 10.4
  • Read requests and send responses through the connected socket. section 10.4

Pizza-ordering service

A local pizza server listens on 127.0.0.1:12345. Netcat connects as a client, sends 10, and receives “Thank you for ordering 10 pizzas!” The server’s terminal appears hung while accept() waits, then reports the client connection and closes it after communication. section 10.4

One listening server socket handles clients sequentially unless the design adds concurrency. A threaded server keeps the listening socket in the main thread and gives each client connection to a separate thread. An asynchronous server instead makes socket operations nonblocking and lets an event loop resume them when I/O is ready. section 10.6 section 12.8

# 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()

Browse a compact Python server implementation showing create_server(), accept(), receiving data, and the listening-versus-connected socket distinction. section 10.4

How Grokking Concurrency covers it

How deep it goes
Explains binding, listening, blocking accept(), connected sockets, threading, and nonblocking event-loop alternatives.
Examples
Uses a local pizza-ordering service, Python socket listings, Netcat clients, threaded handlers, and asynchronous socket code.
What it assumes
Assumes basic client-server communication while introducing socket binding, listening, accepting, and connection handling through examples.
What you can do after
Build it from scratch as a Python service that binds, listens, accepts clients, and communicates through connection sockets.
How it connects
Connects server sockets with client connections, threads, nonblocking I/O, coroutines, Futures, and event loops.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Grokking Concurrency. The section links point to the parts of the book it draws on.