📺 Watch the Architecture & Live Demo Video
A lightweight, highly stable local Peer-to-Peer (P2P) chat application built from scratch for Windows using C++17 and the Qt 5.15.2 framework. The architecture is completely decentralized, eliminating the need for a central server by utilizing UDP socket broadcasts for real-time peer discovery and persistent, duplex TCP connections for message transport.
The system is divided into four highly focused, single-responsibility modules interacting via Qt's signals and slots mechanism:
-
PeerManager (UDP Subnet Discovery): Enables decentralization by broadcasting UDP heartbeats every 2.5 seconds on port
45454usingQUdpSocket. These heartbeats contain JSON-serialized metadata, including the peer's chosen username and local TCP listening port. The module queries active local network interfaces (filtering out loopback and virtual interfaces) to identify local subnet broadcast targets (e.g.,255.255.255.255or subnet-specific broadcasts). It maintains an in-memoryQMap<QString, PeerInfo>mapping usernames to details. A local sweep timer runs at 2.0-second intervals to check peer activity; if no heartbeat is received from a peer within an 8.0-second threshold, that peer is removed from the active map and the UI is updated immediately. -
ChatManager (Persistent Duplex TCP Transport): To exchange chat messages,
ChatManagerstarts aQTcpServeron an OS-assigned ephemeral port (port0at bind time). Upon discovering a peer via UDP, sending a message initiates a persistent TCP connection to the peer's listening port. Once connected, a custom handshake packet containing the local user's username is sent. To eliminate race conditions and avoid duplicate TCP sockets between the same pair of users, only a single socket connection is registered in the connection mapQMap<QString, QTcpSocket*> m_connections(keyed by the remote peer's username). If both users initiate a connection simultaneously, the connection initiated by the lexicographically smaller username takes precedence, and the redundant socket is safely discarded. TCP stream fragmentation is mitigated usingQDataStreamserialization, prepending each packet with a 4-byte (quint32) size header. When a socket receives data, the receiver buffers incoming bytes until the full payload size indicated by the header is available, ensuring complete message packets are parsed. -
DatabaseManager (User-Isolated File Persistence): To support message history without database dependencies,
DatabaseManagerhandles structured text file writing and parsing. Messages are saved in user-centric log files (e.g.,chat_history_Username.txt). Newlines and escape characters in the message content are encoded (with\n,\r, and\\) using custom escape routines to serialize each chat record onto a single line. This format guarantees that concurrent testing of multiple local instances in the same working directory avoids cross-instance file lock collisions, as each instance reads and writes to a file prefixed with its own sanitized username. -
MainWindow (Programmatic QSS UI): The interface is constructed entirely via C++ layout code—without the use of Qt Designer
.uifiles—to eliminate UI compiler dependencies and ensure absolute layout stability. It applies a modern, custom Qt Style Sheet (QSS) layout modeled after modern chat applications (incorporating a#17212bsidebar/header and a#0e1621chat canvas). Since standardQTextBrowserinstances do not support dynamic width adjustment for message bubbles, bubbles are rendered using HTML<table>structures inside the browser window. Settingalign="left"(for incoming messages) oralign="right"(for outgoing messages) forces the table cells to automatically wrap and fit the text width, delivering a polished user experience.
Follow these steps to compile and run the application on Windows:
-
Prerequisites:
- Windows 10/11 OS.
- Qt 5.15.2 (Miniconda distribution recommended, with binaries placed in
C:\Users\Dell\miniconda3\Library\bin). - MSVC 2019 Build Tools (installed with Visual Studio 2019 or standalone).
-
Compilation via Automated Tooling:
- Open the Native Tools Command Prompt for VS 2019 (x64 or x86 depending on the targeted architecture).
- Navigate to the project root directory.
- Execute the build script:
build.bat
- Technical Explanation: The
build.batscript initializes the compiler environment variables by callingvcvarsall.bat x64, appends the Qt bin path to the local command promptPATHvariable, runsqmake -makefile -spec win32-msvc LANChat.proto generate the MSVC-compatible Makefile, and executesnmaketo build the optimized Release binary located inrelease\LANChat.exe.
-
Execution Environment:
- Run the launcher script from the project root:
run.bat
- Technical Explanation: The
run.batscript appends the required Qt DLL paths to the sessionPATHvariable and spawnsrelease\LANChat.exein the background, resolving all dynamic library dependencies.
- Run the launcher script from the project root:
Use this deterministic validation protocol to verify the decentralized discovery and chat loops:
- Local Multi-Instance Testing:
- Open two separate command windows in the project root.
- Launch a separate instance from each window using
run.bat. - Change the username of the first instance to
Aliceand the second instance toBobvia the "Change Name" button. - With visibility toggled ON (indicated by the teal-colored "Visible" button state), verify that
AliceandBobinstantly discover each other and appear in their respective left-hand panel lists within 2.5 seconds. - Select
Bobin Alice's list, type a message, and click Send. Confirm the message appears as a right-aligned blue bubble on Alice's window and a left-aligned gray bubble on Bob's window. - Click the "Visible" button on Alice's window to turn visibility OFF. Observe Bob's window: verify that Alice disappears from Bob's list exactly 8.0 seconds after the final broadcast, conforming to the network timeout sweep rule.
- Toggle Alice's visibility back to ON. Verify she reappears in Bob's sidebar within the 2.5-second heartbeat window.
- Close the application. Verify that
chat_history_Alice.txtandchat_history_Bob.txthave been created in the working directory containing escaped, single-line log entries for all transmitted messages.