A production-ready, concurrent TCP chat server written in Go. Designed for high throughput, observability, and stability.
- Concurrency Safe: Implements
sync.Mutexlocking to prevent race conditions on shared state (client maps) and file I/O (chat history). - Observability: Integrated Prometheus Metrics endpoint (
:2112/metrics) for real-time monitoring of active connections, message throughput, and Goroutine usage. - Graceful Shutdown: Intercepts
SIGINT/SIGTERMsignals to politely disconnect clients and close listeners before process termination, preventing zombie connections. - Custom Protocol: Defines a strict TCP-text protocol for reliable message framing and command handling.
- Go (1.19+)
- Netcat (
nc) for testing (optional)
The server defaults to port 8989 and exposes metrics on 2112.
# Run from project root
go run src/server/main.go [port]
# Example
go run src/server/main.go 8989
Connect a Client
You can use the included Go client (which handles UI/terminal modes) or standard nc.
Using Go Client:
go run src/client/main.go [IP] [Port]
Using Netcat:
nc localhost 8989
Monitor Metrics
Check the health of the system in real-time:
curl localhost:2112/metrics | grep netcat
Output:
netcat_active_connections 2
netcat_messages_total 45
📂 Architecture & Protocol
Message Protocol
Messages are streamed as byte slices. The first 4 bytes define the command type, enabling efficient switching logic without complex parsing overhead.
Command,Description,Server Response
name,Client requests to set/change display name.,[]byte{0} (ACK)
text,Broadcasts a message to all connected clients.,[]byte{0} (ACK)
hist,Requests the full chat history from disk.,Stream of bytes (history file)
quit,Client signals intent to disconnect.,Connection closed server-side.
Concurrency Model
Client Handling: Each connection triggers a dedicated Goroutine, ensuring blocking I/O on one client does not stall the server.
Message Bus (Client-Side): The client implementation uses a []byte channel as a queue, decoupling user input collection from network transmission.
Persistence
Chat history is stored in history.txt. Access is protected by a Mutex Lock to ensure that concurrent writes from multiple clients do not interleave or corrupt the file.
Connection Limits
The server enforces a hard limit of 10 concurrent connections. It pauses the TCP listener when the limit is reached and automatically resumes accepting connections when a slot frees up.
⚠️ Client Terminal Note
Applies only when using the Go Client implementation.
The client disables input buffering and terminal echo to provide a seamless chat UI. Please use the /quit command to exit the Go client. Force-quitting (Ctrl+C) while using the client may leave your terminal in a raw state (no echo). Note: The Server fully supports Ctrl+C and will shut down gracefully.