<?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>DEV Community: Houda Bachr</title>
    <description>The latest articles on DEV Community by Houda Bachr (@houda_bachr_6190bcf47d311).</description>
    <link>https://dev.to/houda_bachr_6190bcf47d311</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4192338%2Fbf83f78a-6b21-4d8b-b159-3ee7d1e1aded.png</url>
      <title>DEV Community: Houda Bachr</title>
      <link>https://dev.to/houda_bachr_6190bcf47d311</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/houda_bachr_6190bcf47d311"/>
    <language>en</language>
    <item>
      <title>Building a Multi-Client Chat Application with Java Sockets and JavaFX</title>
      <dc:creator>Houda Bachr</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:14:43 +0000</pubDate>
      <link>https://dev.to/houda_bachr_6190bcf47d311/building-a-multi-client-chat-application-with-java-sockets-and-javafx-ej4</link>
      <guid>https://dev.to/houda_bachr_6190bcf47d311/building-a-multi-client-chat-application-with-java-sockets-and-javafx-ej4</guid>
      <description>&lt;p&gt;A group chat is a useful way to explore network programming because several concerns meet in one application: concurrent connections, message delivery, user identity, and a responsive interface. Relay is a small educational project that brings these pieces together using Java TCP sockets, virtual threads, JavaFX, and Maven.&lt;/p&gt;

&lt;p&gt;This article describes the implementation, its main technical challenges, and the checks used to verify it. The project and this write-up were developed with assistance from OpenAI Codex.&lt;/p&gt;

&lt;h2&gt;
  
  
  The application
&lt;/h2&gt;

&lt;p&gt;Relay has a central server and multiple clients. A named user can send messages to the room using a SEND button or Enter. The server adds the sender's name and a timestamp before distributing the message to every connected client, including the sender.&lt;/p&gt;

&lt;p&gt;Users who connect without a username become guests in READ-ONLY MODE. They can receive messages and inspect the active-user list, but cannot send chat messages. The &lt;code&gt;allUsers&lt;/code&gt; command returns the connected-user list privately to its requester. The &lt;code&gt;end&lt;/code&gt; and &lt;code&gt;bye&lt;/code&gt; commands, along with a LEAVE button, close a connection.&lt;/p&gt;

&lt;p&gt;The server interface displays connected users in a live ListView, assigns a random background color to each session, and records connection and message activity. Both applications use JavaFX GridPane layouts and CSS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Organizing the implementation
&lt;/h2&gt;

&lt;p&gt;The project is a Maven reactor with three modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;common:&lt;/strong&gt; runtime configuration and the wire protocol.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;server:&lt;/strong&gt; connection management, membership, message distribution, and the server interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;client:&lt;/strong&gt; the client connection model and chat interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The central design decision is to keep socket logic independent of JavaFX. &lt;code&gt;ChatServer&lt;/code&gt; and &lt;code&gt;ChatClient&lt;/code&gt; contain the network operations. &lt;code&gt;ServerApplication&lt;/code&gt; and &lt;code&gt;ClientApplication&lt;/code&gt; present their state. Listener interfaces connect the two layers without requiring the models to import JavaFX classes.&lt;/p&gt;

&lt;p&gt;The implementation work began with configuration, framing, and the networking models. The interfaces were then connected through listener callbacks. Socket integration tests checked the protocol behavior, followed by automated GUI checks and executable-JAR launch checks. UML diagrams and a three-minute demonstration document the final result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling concurrent clients
&lt;/h2&gt;

&lt;p&gt;A server cannot spend its entire execution waiting for one client to send a message. It must continue accepting connections and servicing existing users.&lt;/p&gt;

&lt;p&gt;Relay uses a virtual-thread executor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The accept loop and individual client handlers run as executor tasks. This lets the implementation use straightforward blocking socket reads while handling multiple connections concurrently. The project targets Java 21 or newer and was tested with Java 22.&lt;/p&gt;

&lt;p&gt;Concurrency also requires protecting shared state. Client membership and broadcasts are synchronized, and writes to each connection are serialized so frames do not interleave. This approach keeps the mini-project understandable, although it has a limitation: a client that stops reading can eventually delay a broadcast. A more scalable design would introduce bounded outgoing queues and separate writer tasks for each connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Giving TCP messages clear boundaries
&lt;/h2&gt;

&lt;p&gt;TCP supplies a stream of bytes, so the application needs its own message boundaries. A raw newline-delimited chat protocol becomes ambiguous when a user writes a multiline message.&lt;/p&gt;

&lt;p&gt;Relay uses this frame format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TYPE&amp;lt;TAB&amp;gt;Base64(UTF-8 payload)&amp;lt;NEWLINE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Encoding the payload allows a message to contain newlines or tabs without breaking the frame structure. UTF-8 supports international text and emoji. Base64 is only an encoding; it does not encrypt the conversation.&lt;/p&gt;

&lt;p&gt;The connection begins with &lt;code&gt;HELLO&lt;/code&gt;, containing the requested username. The server replies with &lt;code&gt;WELCOME&lt;/code&gt; and &lt;code&gt;MODE&lt;/code&gt;. Later frames distinguish chat messages, system notices, private user lists, errors, and leave requests.&lt;/p&gt;

&lt;p&gt;The implementation bounds frame length and limits chat messages to 4,000 characters. A ten-second handshake timeout prevents a connection from waiting indefinitely for its initial identity message.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforcing read-only mode in two places
&lt;/h2&gt;

&lt;p&gt;Disabling a button improves the interface, but it cannot enforce a network rule by itself. Another client could bypass that interface and send a frame directly.&lt;/p&gt;

&lt;p&gt;Relay therefore enforces guest restrictions in both the UI and the server. A guest's composer and SEND button are disabled. Independently, the server checks the session's read-only flag and rejects attempts to send chat messages. Guests can still request the active-user list and leave normally.&lt;/p&gt;

&lt;p&gt;Named users must also pass validation, and duplicate names are rejected without regard to case. This is username-based identification rather than password authentication: the application does not implement accounts or prove ownership of a name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping JavaFX responsive
&lt;/h2&gt;

&lt;p&gt;Socket operations should not block the JavaFX Application Thread. Connection and send operations run outside that thread, and the client receives messages in a virtual thread.&lt;/p&gt;

&lt;p&gt;When a model emits a callback, the view schedules its visual update through &lt;code&gt;Platform.runLater&lt;/code&gt;. This keeps the networking model independent of JavaFX while ensuring that controls are updated on the correct thread.&lt;/p&gt;

&lt;p&gt;The same separation makes testing easier. Networking tests instantiate &lt;code&gt;ChatServer&lt;/code&gt; and &lt;code&gt;ChatClient&lt;/code&gt; directly, without opening a window or starting JavaFX.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commands, configuration, and disconnection
&lt;/h2&gt;

&lt;p&gt;Ordinary messages are broadcast, but &lt;code&gt;allUsers&lt;/code&gt; receives a direct reply on the requester's connection. This avoids exposing command responses to the whole room. A dedicated WHO'S ONLINE button provides the same operation for guests whose composer is disabled.&lt;/p&gt;

&lt;p&gt;The disconnection paths remove the user from server membership, update the displayed list, and notify the remaining clients. Closing a window or losing a connection also requires cleanup; abrupt disconnects are covered by the socket tests.&lt;/p&gt;

&lt;p&gt;Network settings live in an external file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;server.host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;
&lt;span class="py"&gt;server.bind&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
&lt;span class="py"&gt;server.port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The applications read this file at runtime. Client command-line arguments can override the destination host and port, allowing deployment changes without recompilation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification and final implementation
&lt;/h2&gt;

&lt;p&gt;The recorded clean Maven build passed &lt;strong&gt;12 JUnit tests&lt;/strong&gt;. They exercise real loopback TCP sockets and cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;24 concurrent clients and message delivery to all recipients;&lt;/li&gt;
&lt;li&gt;timestamped Unicode and multiline messages;&lt;/li&gt;
&lt;li&gt;private active-user replies and server-side rejection of guest writes;&lt;/li&gt;
&lt;li&gt;invalid and duplicate usernames;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;end&lt;/code&gt;, &lt;code&gt;bye&lt;/code&gt;, LEAVE, abrupt disconnects, and server shutdown;&lt;/li&gt;
&lt;li&gt;oversized messages, invalid frames, configuration overrides, and client lifecycle behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An automated GUI demonstration also passed &lt;strong&gt;12 checks&lt;/strong&gt;, including SEND, Enter, guest restrictions, private replies, leaving, and reconnection. Separate launch checks confirmed that the packaged server and client start as independent Java processes.&lt;/p&gt;

&lt;p&gt;The three-minute video combines a source walkthrough with real JavaFX controls communicating over local TCP sockets. Its recorder hosts the application views in one JVM; the delivered launchers run separately. These checks establish the tested local behavior, rather than claiming production-scale reliability or testing across every operating system.&lt;/p&gt;

&lt;p&gt;The deliverables include two executable JARs, Maven source, configuration, class and deployment diagrams, a sequence diagram, and the demo video. The bundled JARs were built for macOS Apple Silicon. Other platforms should rebuild the project so Maven selects matching JavaFX native libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the project
&lt;/h2&gt;

&lt;p&gt;From the extracted project directory, build and test with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./mvnw clean verify
./scripts/package.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then start the server and clients in separate terminals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-jar&lt;/span&gt; dist/TCPServer.jar
java &lt;span class="nt"&gt;-jar&lt;/span&gt; dist/TCPClient.jar localhost 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows, use &lt;code&gt;mvnw.cmd clean verify&lt;/code&gt; and copy the generated server and client JARs from their module &lt;code&gt;target&lt;/code&gt; directories into &lt;code&gt;dist&lt;/code&gt;. Keep &lt;code&gt;chat.properties&lt;/code&gt; in the working directory, or specify another file using the &lt;code&gt;chat.config&lt;/code&gt; system property.&lt;/p&gt;

&lt;h2&gt;
  
  
  What could come next
&lt;/h2&gt;

&lt;p&gt;This version focuses on the assignment's shared-room behavior. Useful extensions would include outgoing message queues, encrypted transport, authenticated accounts, and persistent message history. Each would introduce additional responsibilities that should remain separate from the JavaFX views.&lt;/p&gt;

&lt;p&gt;The main lesson from this implementation is that a reliable chat interface depends on clear protocol boundaries, server-side rules, careful connection cleanup, and explicit coordination between networking and UI threads.&lt;/p&gt;

&lt;p&gt;Project repository: &lt;a href="https://github.com/houda27/Multi-Client-Chat-Application-Using-Java-Sockets" rel="noopener noreferrer"&gt;Multi-Client Chat Application Using Java Sockets&lt;/a&gt;. Access to this private repository requires the owner's permission.&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
