thecodex.expert · The Codex Family of Knowledge
Tier 3 · Upper-Intermediate · Python Project

Socket Chat Server

Build a chat server that multiple clients connect to and exchange messages in real time. Learn raw networking with sockets.

🧠 Teaches how to think spoonfed, every age Last verified:

1 The Problem

We want a chat server: several people connect over the network and every message one sends is broadcast to all the others, live. It teaches socket programming — the raw networking beneath every chat app, game server, and real-time service — plus handling many connections at once.

Where this shows up: chat apps, multiplayer games, live dashboards, trading systems, IoT devices, anything real-time. Sockets are the foundation under WebSockets and every networked application.

2 How to Think About It

Think about how a server handles many clients, before any code:

The plan — in plain English
1. The server listens on a port for connections. → 2. Each client that connects gets its own thread, so one slow client does not block the others. → 3. When a message arrives from one client, the server broadcasts it to every other connected client. → 4. On disconnect, remove that client.

Yes

Server listens on a port

Client connects

Give client its own thread

Wait for a message

Broadcast to all other clients

Disconnected?

Remove client

3 The Build — explained part by part

Here is a complete chat server. The broadcast logic is separated so it can be tested. Each part is explained below.

Pythonchat_server.py
import socket
import threading

clients = []      # every connected client socket

def broadcast(message, sender, client_list):
    # Send a message to everyone except the sender.
    for client in client_list:
        if client is not sender:
            try:
                client.send(message)
            except OSError:
                pass      # client gone; ignore

def handle_client(client):
    while True:
        try:
            message = client.recv(1024)
            if not message:
                break
            broadcast(message, client, clients)
        except OSError:
            break
    clients.remove(client)
    client.close()

def start(host="localhost", port=9000):
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((host, port))
    server.listen()
    print(f"Chat server on {host}:{port}")
    while True:
        client, address = server.accept()
        clients.append(client)
        # Each client runs in its own thread.
        threading.Thread(target=handle_client, args=(client,)).start()

if __name__ == "__main__":
    start()
What each part does — in plain words
import socket, threadingsocket is the raw network connection; threading lets us handle many clients at once.

broadcast(message, sender, client_list) — the core: send the message to every client except the one who sent it. We pull this out as its own function so we can test it without a real network.

handle_client — runs for each connected client: wait for a message (recv), broadcast it, repeat. An empty message means they disconnected, so we break and clean up.

server.bind / listen / accept — the standard server setup: claim a port, listen for connections, and accept each one. accept() waits until someone connects.

threading.Thread(target=handle_client, ...).start() — the key to handling many clients: each gets its own thread, so they run independently and one cannot block another.
Common mistakes — and how to avoid them
✗ Handling clients without threads — one client blocks everyone else.
✓ Give each client its own thread so they run independently.
✗ Sending the message back to the sender — they see their own message echoed.
✓ Skip the sender in the broadcast loop.
✗ Letting one broken connection crash the loop — everyone gets disconnected.
✓ Wrap each send in try/except so one failure is isolated.

4 Test & Prove Each Part

Live networking is hard to test, so we test the broadcast logic with fake client objects that just record what they receive.

A message is sent to other clients
The sender does not receive their own message
A broken client does not crash the broadcast
Pythontest_chat.py
def broadcast(message, sender, client_list):
    for client in client_list:
        if client is not sender:
            try:
                client.send(message)
            except OSError:
                pass


class FakeClient:
    """A stand-in for a real socket that records messages."""
    def __init__(self, broken=False):
        self.received = []
        self.broken = broken

    def send(self, message):
        if self.broken:
            raise OSError("broken pipe")
        self.received.append(message)


def test_others_receive():
    """Other clients get the message."""
    a, b = FakeClient(), FakeClient()
    broadcast(b"hi", a, [a, b])
    assert b.received == [b"hi"]


def test_sender_excluded():
    """The sender does not receive their own message."""
    a, b = FakeClient(), FakeClient()
    broadcast(b"hi", a, [a, b])
    assert a.received == []


def test_broken_client_ignored():
    """A broken client does not stop the broadcast."""
    a, broken, c = FakeClient(), FakeClient(broken=True), FakeClient()
    broadcast(b"hi", a, [a, broken, c])
    assert c.received == [b"hi"]      # c still gets it

Run with pytest -v. The FakeClient trick lets us test broadcast logic without any real sockets — fast and reliable. The broken-client test proves one bad connection will not take down the whole chat.

5 The Interface

CONNECTlocalhost:9000join the chat
SENDa messagebroadcast to all others
Flow
Client A sends: "Hello"
Clients B, C receive: "Hello"
Client A does not

6 Run It & Automate It

Run it locally
python3 chat_server.py
Then connect with several terminals: nc localhost 9000 (or telnet). Type in one — it appears in the others.

Jenkins runs the tests automatically — each line explained below.

What you should see when it works
Terminala real run
Chat server on localhost:9000
# Client A types "Hello" → Clients B and C see "Hello"
If it breaks — how to fix it
🚨 OSError: Address already in use.
A previous server is still holding the port. Wait a moment or use a different port.
🚨 Messages do not reach other clients.
Check clients are added to the shared list and broadcast iterates over it.
GroovyJenkinsfile
// Jenkinsfile — automated tests on every change.
pipeline {
    agent any
    stages {
        stage('Get the code') { steps { checkout scm } }       // download the code
        stage('Install') { steps { sh 'python3 -m venv venv && . venv/bin/activate && pip install pytest' } }  // test tool
        stage('Test') { steps { sh '. venv/bin/activate && pytest -v' } }   // run every test
    }
    post {
        success { echo 'All tests passed.' }
        failure { echo 'A test failed — look above.' }
    }
}
🎯 Try this next — make it yours
  1. Usernames. Prefix each message with who sent it. (Teaches: per-client state.)
  2. Join/leave notices. Announce when people connect or disconnect. (Teaches: system messages.)
  3. Private messages. Direct a message to one user. (Teaches: routing.)
What you learned
You learned socket programming — listening, accepting connections, and broadcasting — plus handling many clients with threads, and the FakeClient technique for testing network code. Sockets underlie every real-time application. Related: socket, Concurrency.