A multi-threaded client-server application demonstrating distributed computing, concurrent task processing, and real-time network communication in Java.
The server accepts multiple simultaneous TCP connections via a thread pool, processes text commands, and logs all activity with timestamps. The Swing-based client provides a dark-themed terminal-style GUI with asynchronous message handling and color-coded output.
| Feature | Description |
|---|---|
| Thread-Pool Concurrency | Fixed-size ExecutorService handles up to 10 simultaneous clients without spawning unbounded threads |
| Command Processing | 10 built-in commands: echo, upper, lower, reverse, count, length, replace, time, ping, help |
| Timestamped Logging | All connections, commands, and responses logged to server.log with yyyy-MM-dd HH:mm:ss timestamps |
| Graceful Shutdown | Shutdown hook cleanly terminates the thread pool and flushes logs on Ctrl-C |
| Client Tracking | Each client gets a unique ID for log traceability |
| Null-Safe Reads | Handles abrupt client disconnects without NullPointerException |
| Feature | Description |
|---|---|
| Dark Terminal UI | Monospaced dark-themed Swing interface with color-coded messages |
| Async Reader Thread | Background thread receives server messages without blocking the UI |
| Timestamped Messages | Sent and received messages display [HH:mm:ss] timestamps |
| Status Bar | Live connection status indicator at the bottom of the window |
| Clean Disconnect | Window close handler sends goodbye and releases all resources |
| EDT-Safe | All GUI operations run on the Event Dispatch Thread |
| Command | Example | Result |
|---|---|---|
echo <msg> |
echo hello |
Echo: hello |
upper <msg> |
upper hello |
HELLO |
lower <msg> |
lower HELLO |
hello |
reverse <msg> |
reverse hello |
olleh |
count <msg> |
count hello world |
Word count: 2 |
length <msg> |
length hello |
Length: 5 |
replace <old> <new> <msg> |
replace l r hello |
herro |
time |
time |
Server date and time |
ping |
ping |
pong |
help |
help |
Lists all commands |
bye |
bye |
Disconnects |
ββββββββββββββββββββ TCP :12345 βββββββββββββββββββββ
β Client (Swing) β βββββββββββββββββββββββββββΊ β Server β
β β text commands / responses β β
β ββββββββββββββ β β βββββββββββββββ β
β β GUI Thread β β β β Main Thread β β
β β (EDT) β β β β accept() β β
β ββββββββββββββ β β ββββββββ¬βββββββ β
β ββββββββββββββ β β β β
β β Reader β β β ββββββββΌβββββββ β
β β Thread β β β β ThreadPool β β
β ββββββββββββββ β β β (10 workers)β β
ββββββββββββββββββββ β ββββββββ¬βββββββ β
β β β
β ββββββββΌβββββββ β
β βClientHandlerβ β
β β (per client)β β
β ββββββββ¬βββββββ β
β β β
β ββββββββΌβββββββ β
β β server.log β β
β βββββββββββββββ β
βββββββββββββββββββββ
RunnableoverThreadβClientHandlerimplementsRunnableand is submitted to anExecutorService, not subclassed fromThread.- Shared synchronized logger β A single
PrintWriterwithsynchronizedaccess prevents log interleaving from concurrent handlers. - Null-safe read loop β
while ((line = reader.readLine()) != null)handles abrupt disconnects without crashing. - Background reader thread β The client reads server responses on a dedicated thread, preventing GUI freezes on
readLine(). - EDT compliance β All Swing UI mutations happen on the Event Dispatch Thread via
SwingUtilities.invokeLater(). - Try-with-resources β Server uses try-with-resources on the socket, reader, and writer for guaranteed cleanup.
- Java 11+ (uses
var, text blocks,String.isBlank(),java.time)
git clone https://github.com/shuddha2021/Distributed-Java-App.git
cd Distributed-Java-AppTerminal 1 β Start the server:
javac src/Server.java -d out
java -cp out ServerTerminal 2 β Start a client:
javac src/Client.java -d out
java -cp out ClientYou can launch multiple client instances to test concurrent connections.
Once connected, type these commands in the client:
help
echo Hello, World!
upper distributed systems
reverse networking
count Java is awesome
time
ping
bye
Distributed-Java-App/
βββ src/
β βββ Server.java β multi-threaded server with command processor and logging
β βββ Client.java β Swing GUI client with async reader and dark theme
βββ .gitignore β ignores build artifacts, IDE files, and logs
βββ README.md
| Concern | Implementation |
|---|---|
| Language | Java 11+ |
| Networking | java.net.ServerSocket, java.net.Socket β raw TCP sockets |
| Concurrency | ExecutorService with fixed thread pool, AtomicInteger for client IDs |
| GUI | Swing (JFrame, JTextPane, StyledDocument) with dark theme |
| Logging | Timestamped file logging via java.time.LocalDateTime |
| I/O | BufferedReader / PrintWriter with try-with-resources |
| Bug | Fix |
|---|---|
ServerThread extends Thread submitted to ExecutorService |
Changed to ClientHandler implements Runnable |
readLine() null not checked β NullPointerException on client disconnect |
while ((line = reader.readLine()) != null) loop |
Each thread opened its own FileWriter("server.log") β race condition |
Single shared PrintWriter with synchronized log method |
Socket, reader, writer not closed in finally |
Try-with-resources on all I/O resources |
Client created new BufferedReader on every sendCommand() |
Single reader on a background thread |
| GUI not built on EDT | SwingUtilities.invokeLater() in main() |
Debug System.out.println left in client |
Removed |
No ExecutorService shutdown |
Shutdown hook added |
count used .split(" ") (double spaces = empty tokens) |
Changed to .split("\\s+") |
Contributions welcome. Ideas for extension:
- SSL/TLS encrypted connections
- User authentication and session management
- Persistent command history
- File transfer protocol
- REST API alongside raw sockets
- Unit tests with JUnit
Fork the repo, create a feature branch, and submit a pull request.
MIT