A LAN-based terminal chat application built in Rust using asynchronous TCP networking with Tokio.
- 🌐 TCP-based LAN chat - Connect multiple users on the same network
- 🔐 Server-controlled identity -
[username@ip]format, prevents spoofing - 🎨 Colored terminal output - Different colors for users and system messages
- 📡 Async architecture - Built on Tokio for efficient concurrent handling
- 💬 Private messaging - Send direct messages with
/pm - 👥 User listing - See who's online with
/who
rchat/
├── Cargo.toml
└── src/
├── server/
│ ├── main.rs # Server entry point, connection handling
│ ├── hub.rs # Central message router, client registry
│ ├── client.rs # Per-connection handler
│ ├── identity.rs # Client identity management
│ └── protocol.rs # JSON message protocol definitions
└── client/
├── main.rs # Client entry point, connection setup
├── input.rs # Terminal input handling, command parsing
├── receiver.rs # Message receiving and display
└── protocol.rs # JSON message protocol definitions
cargo build --releasecargo run --bin serverThe server binds to 0.0.0.0:8080 by default.
cargo run --bin client <server_ip:port>
# Examples:
cargo run --bin client 127.0.0.1:8080 # localhost
cargo run --bin client 192.168.1.10:8080 # LAN IP| Command | Description |
|---|---|
/who |
List all connected users |
/pm <user@ip> <message> |
Send a private message |
/quit or /exit |
Disconnect from the server |
Messages are JSON-encoded with the following structure:
{
"type": "message",
"content": "hello world",
"sender": "harsh@192.168.1.23",
"timestamp": "14:30:45"
}| Type | Description |
|---|---|
join |
Client joining the server |
message |
Regular chat message |
system |
Server announcements |
leave |
Client disconnecting |
who |
Request user list |
privatemessage |
Private message to specific user |
The application uses Tokio's async runtime with the following concurrency patterns:
-
Server Hub (Actor Pattern)
- Central hub runs as a single task
- Receives messages via
mpscchannel - Maintains client registry in a
HashMap - No shared mutable state - all state is local to the hub
-
Client Handlers
- Each connection spawns a dedicated handler task
- Bidirectional communication via
tokio::select! - Sends to hub via channel, receives via dedicated channel
-
Client Tasks
- Input task: Reads stdin, parses commands, sends to server
- Receiver task: Reads from server, displays formatted messages
- Writer task: Sends messages from channel to TCP stream
┌─────────────────────────────────────────────────────────────┐
│ SERVER │
│ ┌─────────┐ │
│ │ Hub │◄──── HubMessage channel ◄──┬──┬──┬── │
│ │ │ │ │ │ │
│ │ clients │ │ │ │ │
│ │ map │─────► Per-client channels ─►│ │ │ │
│ └─────────┘ │ │ │ │
│ │ ┌──┴──┴──┴──┐ │
│ │ │ Client │ │
│ └───────────────────────────────│ Handlers │ │
│ └───────────┘ │
└─────────────────────────────────────────────────────────────┘
- Client sends only system username (
$USERenv var) in join message - Server extracts IP from
socket.peer_addr() - Server constructs identity:
username@ip - Port is stored internally for uniqueness (multiple connections from same user/IP)
- Client cannot spoof identity - server always controls it
1. Parse args (server address)
│
▼
2. Get $USER environment variable
│
▼
3. TCP connect to server
│
▼
4. Send join message with username
│
▼
5. Receive identity confirmation
│
▼
6. Spawn tasks: input, receiver, writer
│
▼
7. Run until quit or disconnect
│
▼
8. Clean shutdown
- No TLS - Messages are transmitted in plaintext
- No authentication - Any user can connect with any username
- LAN use only - Not designed for internet exposure
- Server-controlled identity - IP cannot be spoofed by client
Server Output:
🌐 Server listening on 0.0.0.0:8080
📡 Clients can connect using your LAN IP on port 8080
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔗 New connection from 192.168.1.23:54321
✅ 192.168.1.23:54321 authenticated as [harsh@192.168.1.23]
>>> harsh@192.168.1.23 joined
📊 Active clients: 1
Client Output:
Connecting to 192.168.1.10:8080
Username: harsh
Connected!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Type your message and press Enter to send.
Commands: /who, /pm <user@ip> <message>, /quit
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[14:30:45] Welcome to rchat! You are connected as [harsh@192.168.1.23]
>>> harsh@192.168.1.23 joined
harsh@192.168.1.23 > hello everyone!
[14:30:52] [harsh@192.168.1.23] hello everyone!
MIT