<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ilyass Bartal</title>
    <description>The latest articles on Forem by Ilyass Bartal (@ilyassbartal).</description>
    <link>https://forem.com/ilyassbartal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3806719%2Fbbf31728-8165-4163-a9a7-477d9b775083.png</url>
      <title>Forem: Ilyass Bartal</title>
      <link>https://forem.com/ilyassbartal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ilyassbartal"/>
    <language>en</language>
    <item>
      <title>Group Chat Application</title>
      <dc:creator>Ilyass Bartal</dc:creator>
      <pubDate>Thu, 05 Mar 2026 00:42:36 +0000</pubDate>
      <link>https://forem.com/ilyassbartal/group-chat-application-4f3d</link>
      <guid>https://forem.com/ilyassbartal/group-chat-application-4f3d</guid>
      <description>&lt;p&gt;&lt;strong&gt;Building a Multi-Client TCP Chat System in Java (JavaFX + Maven)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overview&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For our Advanced Programming Paradigms class project, we built a &lt;strong&gt;TCP chat system&lt;/strong&gt; where multiple clients can connect to a server, choose a username, exchange messages in real time, and see a live list of connected users. The project uses &lt;strong&gt;Java sockets&lt;/strong&gt;, &lt;strong&gt;multi-threading&lt;/strong&gt;, &lt;strong&gt;JavaFX&lt;/strong&gt; for the user interface, and &lt;strong&gt;Maven&lt;/strong&gt; for dependency management and builds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requirements implemented&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-client TCP server (each client handled concurrently)&lt;/li&gt;
&lt;li&gt;JavaFX Server UI (start/stop server, log, connected users)&lt;/li&gt;
&lt;li&gt;JavaFX Client UI (join, send messages, receive messages, user list)&lt;/li&gt;
&lt;li&gt;Configuration file for IP/Port (&lt;code&gt;config.properties&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Command-line arguments override configuration&lt;/li&gt;
&lt;li&gt;Clean shutdown (port is released properly after stopping)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Features&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accepts multiple clients simultaneously&lt;/li&gt;
&lt;li&gt;Broadcasts chat messages to all connected clients&lt;/li&gt;
&lt;li&gt;Sends informational events (user joined/left)&lt;/li&gt;
&lt;li&gt;Shows connected users in the Server UI&lt;/li&gt;
&lt;li&gt;Stops cleanly (no “address already in use” after stop)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Client&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connects to server via TCP&lt;/li&gt;
&lt;li&gt;Sends and receives messages&lt;/li&gt;
&lt;li&gt;Shows chat messages + system messages&lt;/li&gt;
&lt;li&gt;Displays the list of connected users&lt;/li&gt;
&lt;li&gt;Reads default IP/port from config file&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Architecture (multi-module Maven)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I organized the project as a &lt;strong&gt;multi-module Maven project&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TCPServer&lt;/code&gt; module (server-side logic + server JavaFX UI)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TCPClient&lt;/code&gt; module (client networking + client JavaFX UI)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation makes the code easier to understand and closer to real-world architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Main server classes&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ChatServer&lt;/code&gt;: owns the &lt;code&gt;ServerSocket&lt;/code&gt;, accepts connections, manages connected clients.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ClientHandler&lt;/code&gt;: one instance per client; runs in its own thread.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ServerListener&lt;/code&gt;: interface used to notify the UI about user list/log changes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ServerController&lt;/code&gt;: JavaFX controller; starts/stops the server and updates UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Main client classes&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ChatClient&lt;/code&gt;: opens a socket, sends/receives lines, runs a background listener thread.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ClientListener&lt;/code&gt;: interface used to push events/messages to the UI.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ChatController&lt;/code&gt;: JavaFX controller; reacts to events and updates UI.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Communication protocol&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Messages are sent as simple text lines using a small protocol, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;JOIN|username&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MSG|username|message&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;INFO|some text&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;USERS|user1,user2,user3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach keeps parsing simple and deterministic.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Key programming paradigms used&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Concurrency (multi-threading)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The server accepts clients in a loop. For each connection, it spawns a new thread with a &lt;code&gt;ClientHandler&lt;/code&gt;.&lt;br&gt;
This allows multiple clients to chat at the same time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Thread-safe collections&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The server stores connected clients in a:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ConcurrentHashMap&amp;lt;String, ClientHandler&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This avoids race conditions when multiple client threads connect/disconnect at the same time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) Listener (Observer-style) pattern for UI updates&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;JavaFX UI updates must run on the UI thread.&lt;br&gt;
To keep networking code independent from UI, I used interfaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ServerListener&lt;/code&gt; (server → server UI)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ClientListener&lt;/code&gt; (client → client UI)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The UI controller implements the listener and updates JavaFX components safely (using &lt;code&gt;Platform.runLater&lt;/code&gt; where needed).&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Technical challenges and how I fixed them&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge 1: “Address already in use: bind”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We often got this error after restarting the server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it happens when port 3000 is still occupied by a running process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Root cause:&lt;/strong&gt; the server socket wasn’t being closed properly, or a second server run was started accidentally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; store &lt;code&gt;ServerSocket&lt;/code&gt; as a class field and close it in &lt;code&gt;stopServer()&lt;/code&gt; so the port is released:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;serverSocket.close()&lt;/code&gt; unblocks &lt;code&gt;accept()&lt;/code&gt; and stops the server loop&lt;/li&gt;
&lt;li&gt;also removed/avoided duplicate run configurations that started another server on the same port&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenge 2: Duplicate usernames and concurrency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two clients could attempt to register the same username at almost the same time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; use atomic insertion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;clients.putIfAbsent(username, handler)&lt;/code&gt;
If the username already exists, registration fails immediately without extra locking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenge 3: JavaFX + networking thread safety&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Networking runs on background threads, but JavaFX UI must update on the UI thread.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; use listener callbacks and wrap UI updates with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Platform.runLater(() -&amp;gt; { /* update UI */ })&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenge 4: Configuration and runtime flexibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hardcoding &lt;code&gt;localhost:3000&lt;/code&gt; is not flexible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; load defaults from &lt;code&gt;config.properties&lt;/code&gt; and allow override using &lt;code&gt;main(String[] args)&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Client: &lt;code&gt;TCPClient &amp;lt;ip&amp;gt; &amp;lt;port&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Server: &lt;code&gt;TCPServer &amp;lt;port&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;How to run&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A — Run using IntelliJ Maven panel&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Start Server:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maven → &lt;code&gt;TCPServer&lt;/code&gt; → Plugins → &lt;code&gt;javafx&lt;/code&gt; → &lt;code&gt;javafx:run&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click &lt;strong&gt;Start Server&lt;/strong&gt; in the UI&lt;br&gt;
&lt;strong&gt;2. Start Clients:&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Maven → &lt;code&gt;TCPClient&lt;/code&gt; → Plugins → &lt;code&gt;javafx&lt;/code&gt; → &lt;code&gt;javafx:run&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run multiple times for multiple clients&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Option B — Run using IntelliJ “Application” configs (for command-line args)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create a Run Configuration:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Server main class: &lt;code&gt;server.app.TCPServer&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Program args: &lt;code&gt;4000&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Client main class: &lt;code&gt;client.app.TCPClient&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Program args: &lt;code&gt;127.0.0.1 4000&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Final result&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At the end, we had a working chat system where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server UI shows logs + connected users&lt;/li&gt;
&lt;li&gt;Multiple clients can connect and chat concurrently&lt;/li&gt;
&lt;li&gt;Users list updates in real time&lt;/li&gt;
&lt;li&gt;The server stops cleanly and releases the port&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;What we learned&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This project made me much more comfortable with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TCP sockets and simple protocols&lt;/li&gt;
&lt;li&gt;Designing concurrent systems safely&lt;/li&gt;
&lt;li&gt;Thread-safety and shared state (&lt;code&gt;ConcurrentHashMap&lt;/code&gt;, atomic registration)&lt;/li&gt;
&lt;li&gt;Separating networking code from UI using listener patterns&lt;/li&gt;
&lt;li&gt;JavaFX thread rules (&lt;code&gt;Platform.runLater&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Repo :&lt;/strong&gt; &lt;a href="https://github.com/Abdell-EL/Chat_system" rel="noopener noreferrer"&gt;https://github.com/Abdell-EL/Chat_system&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Author:&lt;/strong&gt; Abdellah Elouazzani - Ilyass Bartal - Anouar El Yaagoubi&lt;/p&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>tcp</category>
      <category>maven</category>
    </item>
  </channel>
</rss>
