- Socket-based, multi-threaded chat system built with Python
- Server: uses socket and threading for concurrent client handling
- Client: built with Tkinter, featuring event-driven UI and background message receiver thread
- Data & Security: user authentication via SQLite + SQLAlchemy, secured with SSL/TLS
- Protocol: custom JSON messaging validated by Pydantic
- Lobby and chat presence now refresh in real time; no manual refresh required to see online status changes.
- Password storage now includes a per-user salt, hardening credential security.
-
The server is implemented using a multi-threaded architecture. Each incoming connection spawns a new thread.
-
Each thread is managed by a ClientHandler, which operates as a state machine to handle the full client interaction lifecycle.
-
Concurrency Control
To ensure data consistency in a multi-threaded environment, shared in-memory session data (e.g., online_users, chat_rooms) is managed through a ChatData structure protected by a reentrant mutex lock.
-
Database
User credentials (username and password) are stored in a SQLite database, accessed via SQLAlchemy Core.
-
Security
- Passwords are hashed before being stored.
- All client-server communication is secured using SSL/TLS encryption.
In the diagram, blue arrows represent server responses/pushes, and red arrows represent user-triggered UI requests.
-
The client’s main thread runs a Tkinter event loop, which handles both UI events (e.g., button clicks, message sending) and server responses or push events.
-
Decoupled Class Design
- ServerHandler manages all server communication. To prevent blocking the Tkinter event loop, it runs a dedicated receiver thread that continuously listens for incoming messages from the server and places them into a queue, acting as the producer.
- App runs on the main thread, handling page transitions and serving as the consumer, retrieving messages from the queue and dispatching them to the Dispatcher.
- Dispatcher is responsible for event routing—it establishes relationships between events and callbacks without requiring awareness of individual UI pages. Each page (LoginPage, LobbyPage, ChatRoomPage) registers its callbacks with the dispatcher.
-
Message Framing
Because TCP may cause packet concatenation (the “sticky packet” issue), the protocol adopts a length-prefixed design. Each message begins with a 4-byte header indicating message length. The application maintains an internal buffer to reconstruct complete messages.
-
Message Format
The client and server communicate using a custom JSON-based protocol, validated using Pydantic to ensure schema correctness.
-
Generating a Self-Signed SSL/TLS Certificate
This project uses a self-signed certificate for demonstration purposes. To generate server.key, server.csr, and server.crt, use the following commands:
# 1. Generate a private key (server.key) openssl genrsa -out server.key 2048 # 2. Create a certificate signing request (server.csr) openssl req -new -key server.key -out server.csr # 3. Generate a self-signed certificate valid for 365 days (server.crt) openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
-
Virtual environment
pip install -r requirements.txt
-
Run the server and client
python server.py python client.py
-
Register an account and log in.
-
On the Lobby page, you can:
- Create a new room
- Enter an existing room
- Log out
- Click the Refresh button to update the list of online users and rooms.
-
On the Chatroom page, you can:
- Send messages
- Refresh the online user list
- Return to the lobby
- To send a private message to a specific user, use the format:
\private <receiver> <your message>
Used for user registration and login.
{ "type": "register", "data": { "username": "harper", "password": "1234" } }
{ "type": "login", "data": { "username": "harper", "password": "1234" } }
Commands available in the lobby state.
{ "type": "list" } // List all online users
{ "type": "logout" } // Log out from the server
{ "type": "enter", "data": { "room": "tech_talk" } } // Enter an existing chatroom
{ "type": "create", "data": { "room": "tech_talk" } } // Create a new chatroom
Commands available after entering a chatroom.
{ "type": "exit" } // Leave current chatroom
{ "type": "list" } // List users in current room
{ "type": "msg", "data": { "from": "sender", "to": "receiver", "text": "Hello everyone!" } } // Send message
-
Success
{ "type": "login|register", "status": "ok", "data": { "username": "harper", "chatroom": "lobby" }, "message": "Login successful" } -
Failure
{ "type": "login|register", "status": "error", "message": "Password incorrect" }
-
User/Room List
{ "type": "list", "status": "ok", "data": { "room1": ["user1", "user2", "user3"], "room2": ["user4"], "room3": [] } } -
Enter Room – Success
{ "type": "enter", "status": "ok", "data": { "username": "username", "room": "chatroom" }, "message": "Welcome to the chatroom" } -
Enter Room – Failure
{ "type": "enter", "status": "error", "message": "Error message" } -
Create Room – Success
{ "type": "create", "status": "ok", "message": "room_name created successfully" } -
Create Room – Failure
{ "type": "create", "status": "error", "message": "Error message" }
-
Exit – Success
{ "type": "exit", "status": "ok", "message": "Exited chatroom, returned to lobby" } -
Exit – Failure
{ "type": "exit", "status": "error", "message": "Error message" } -
New Message (Broadcast or Private)
Success:
{ "type": "msg", "status": "ok", "data": { "to": "public", "from": "sender", "text": "Hello everyone!" } }Error:
{ "type": "msg", "status": "error", "message": "Error message" }
- Add friends



