Advertisement
Open Source Projects by Phil Schwartz

a Python chat server with sockets for LAN communication

LAN chat might sound like a relic, yet it remains useful. A backyard barbecue in Brisbane, a study session at the University of Melbourne, or a small developer workshop in Perth all benefit from messaging that stays on the local network. No cloud provider, no account, no monthly fee.

Python makes this approachable. The standard library ships with socket and threading, providing everything needed to build a chat server without external dependencies. The same code can be extended into a custom tool with minimal friction.

This article walks through building a small but functional chat server for trusted environments such as a home network in Adelaide, a co-working space in Hobart, or a school lab in Canberra. The focus is on clarity, using only the standard library, so the entire program fits on a single screen.

By the end, you will have a working multi-client server, a simple terminal client, and a sense of how to harden the system before sharing it with friends.

Setting up the development environment on Linux

A typical Australian developer workstation in 2026 runs some flavour of Linux, often Ubuntu, Fedora, or Arch, on a laptop tethered to a router connected to the National Broadband Network. Python 3.10 or newer ships with most distributions, so no extra installation is required.

Pick a project directory under ~/projects or ~/code, mirroring conventions from meetups like the Melbourne Python Users Group or PyCon AU. Create a virtual environment to keep dependencies tidy, even though the chat server itself needs none.

A Raspberry Pi works just as well as a desktop. The chat server uses negligible CPU and memory, so it runs happily on older hardware that still does duty as a home server across many Australian suburbs.

Tools you will need

Designing the simple TCP chat protocol

Before writing code, define the wire protocol. For a LAN chat tool, a line-based text protocol over TCP is enough. Each message ends with a newline, and the server forwards every complete line to every other connected client.

Three message types cover the basics: a join notice when a client connects, a chat line carrying the user's text, and a leave notice when a client disconnects. The server tags each chat line with a nickname so receivers know who is speaking. The format is human-readable, which makes testing with netcat easy from a Brisbane café with patchy Wi-Fi.

Because the protocol is line-oriented, the server reads until it sees \n and broadcasts the assembled line. The client does the inverse, wrapping print output with a newline by default. This design avoids the complexity of length-prefixed binary framing.

Implementing the Python server with sockets

The server script begins with two imports from the standard library: socket for the network layer and threading for handling multiple clients. A host constant of 0.0.0.0 tells the operating system to accept connections on every interface.

The main server loop creates a TCP socket, sets SO_REUSEADDR, binds to the chosen port, and listens. When a new client connects, the server spawns a thread dedicated to that client, leaving the main thread free to accept further connections.

Each client thread reads lines from the socket, prefixes the nickname, and pushes the message into a shared broadcast queue. A lock guards the active client list. The pattern is straightforward enough to teach in a single sitting at a Sydney coding bootcamp.

Building the matching client application

The client mirrors the server's socket setup but plays a different role. It opens a TCP connection to the server's IP address, often something like 192.168.0.10 on a home network. The local IP matters more than the public address because traffic stays on the LAN, avoiding ATO data retention concerns.

After connecting, the client prompts for a nickname and starts two threads: one reading from the socket and printing messages, and one reading keyboard input and sending it back. The split avoids the classic problem where a blocking input() call prevents incoming messages from being displayed promptly.

A clean terminal interface uses ANSI escape codes to clear the current line before printing the latest message, so outgoing and incoming text do not collide. Developers familiar with Vim or Emacs will find this approach familiar.

Supporting multiple users with threading

The threading approach scales surprisingly well for small groups. A chat session with a dozen participants spread across suburban Adelaide is well within reach of a single Python process. Each thread spends most of its time blocked on a recv() call, which yields the GIL efficiently.

When a thread sees a closed connection, it removes the client from the shared list, notifies the others, and exits. Errors are caught broadly so a single misbehaving client cannot bring the whole server down. This defensive style suits a community machine, such as the terminals left running at university open days in Perth.

For larger groups, switching to selectors or asyncio removes the per-client thread overhead. The threaded version remains the easiest entry point for newcomers and works fine for households or small offices.

Testing across a home or office LAN

Real testing happens after the code looks right in the editor. Pick two devices on the same network, perhaps a Linux laptop on Wi-Fi and a desktop wired into the router. Start the server on one, run the client on the other, and confirm that messages flow in both directions. Add a third device to verify multi-client behaviour.

Latency on Australian NBN home connections is low enough that typing feels immediate. Slow messages usually mean a Wi-Fi bottleneck, fixed by moving one device onto Ethernet or the 5 GHz band. Telstra, Optus, and TPG gateways all support both bands out of the box.

Run the server on a NUC in the garage and connect from a laptop in the kitchen to test across a VLAN.

Hardening the chat server for safe local use

Even on a trusted LAN, a few precautions are worth taking. Bind to the LAN interface only, or use a firewall rule to block the chosen port from the WAN side of the router. ACSC publishes guidance that covers home networks too, including updating router firmware.

Sanitise control characters and limit nickname length, so a curious user cannot rewrite other terminals or send malformed input. None of this matters for a two-person chat, but it matters once the server runs at a community event or shared makerspace.

Document how to shut the server down cleanly. A KeyboardInterrupt handler in the main thread closes every client socket and joins the worker threads before exiting. Leaving dangling sockets on a Raspberry Pi plugged in behind the TV is a small annoyance that builds up over time.

Common pitfalls on Australian home networks