diff --git a/.project b/.project
new file mode 100644
index 0000000..9f05120
--- /dev/null
+++ b/.project
@@ -0,0 +1,28 @@
+
+
+ ClientServer
+ Project ClientServer created by Buildship.
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectnature
+
+
+
+ 1743445961452
+
+ 30
+
+ org.eclipse.core.resources.regexFilterMatcher
+ node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+
+
+
+
diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 0000000..d230334
--- /dev/null
+++ b/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,13 @@
+arguments=--init-script /home/xeon0x/.var/app/dev.zed.Zed/data/zed/extensions/work/java/jdtls/jdt-language-server-1.46.0-202503271314/configuration/org.eclipse.osgi/58/0/.cp/gradle/init/init.gradle
+auto.sync=false
+build.scans.enabled=false
+connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
+connection.project.dir=
+eclipse.preferences.version=1
+gradle.user.home=
+java.home=/usr/lib64/jvm/java-21-openjdk-21
+jvm.arguments=
+offline.mode=false
+override.workspace.settings=true
+show.console.view=true
+show.executions.view=true
diff --git a/README.md b/README.md
index c940f86..2d82657 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,39 @@
+# ClientServer
+
+## Build
+
+```bash
+./gradlew build
+```
+
+## Run
+
+### Client
+
+```bash
+./gradlew run --args='client'
+```
+
+or
+
+```bash
+./gradlew runServer
+```
+
+### Server
+
+```bash
+./gradlew run --args='server'
+```
+
+or
+
+```bash
+./gradlew runServer
+```
+
+## Documentation
+
```mermaid
sequenceDiagram
Note over Client, Serveur: DatagramSocket("localhost", 66666)
diff --git a/app/.classpath b/app/.classpath
new file mode 100644
index 0000000..282ada5
--- /dev/null
+++ b/app/.classpath
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/.project b/app/.project
new file mode 100644
index 0000000..ecb5e8f
--- /dev/null
+++ b/app/.project
@@ -0,0 +1,34 @@
+
+
+ app
+ Project app created by Buildship.
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.buildship.core.gradleprojectnature
+
+
+
+ 1743445961456
+
+ 30
+
+ org.eclipse.core.resources.regexFilterMatcher
+ node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+
+
+
+
diff --git a/app/.settings/org.eclipse.buildship.core.prefs b/app/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 0000000..b1886ad
--- /dev/null
+++ b/app/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,2 @@
+connection.project.dir=..
+eclipse.preferences.version=1
diff --git a/app/build.gradle b/app/build.gradle
index 990d74d..fc08b4d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -40,3 +40,19 @@ tasks.named('test') {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}
+
+task runServer(type: JavaExec) {
+ description = 'Runs the server'
+ group = 'application'
+ mainClass = application.mainClass
+ classpath = sourceSets.main.runtimeClasspath
+ args = ['--server']
+}
+
+task runClient(type: JavaExec) {
+ description = 'Runs the client'
+ group = 'application'
+ mainClass = application.mainClass
+ classpath = sourceSets.main.runtimeClasspath
+ args = ['--client']
+}
diff --git a/app/src/main/java/clientserver/App.java b/app/src/main/java/clientserver/App.java
index 755f153..658a06e 100644
--- a/app/src/main/java/clientserver/App.java
+++ b/app/src/main/java/clientserver/App.java
@@ -1,5 +1,8 @@
package clientserver;
+import clientserver.client.Client;
+import clientserver.server.Server;
+
public class App {
public String getGreeting() {
@@ -7,8 +10,49 @@ public class App {
}
public static void main(String[] args) {
- System.out.println(new App().getGreeting());
+ String mode = null;
- MistralDirectAPI.main(new String[] {});
+ // Parse arguments
+ for (String arg : args) {
+ switch (arg.toLowerCase()) {
+ case "--client":
+ mode = "client";
+ break;
+ case "--server":
+ mode = "server";
+ break;
+ default:
+ System.out.println("Unknown argument: " + arg);
+ printUsage();
+ return;
+ }
+ }
+
+ // Check if mode is specified
+ if (mode == null) {
+ System.out.println("No mode specified.");
+ printUsage();
+ return;
+ }
+
+ // Execute based on mode
+ switch (mode) {
+ case "client":
+ System.out.println("Starting client...");
+ Client.main(new String[] {});
+ break;
+ case "server":
+ System.out.println("Starting server...");
+ Server server = new Server(6666);
+ server.run();
+ break;
+ }
+ }
+
+ private static void printUsage() {
+ System.out.println("Usage: ./gradlew run --args='option'");
+ System.out.println("Options:");
+ System.out.println(" --client Run in client mode");
+ System.out.println(" --server Run in server mode");
}
}
diff --git a/app/src/main/java/clientserver/Client.java b/app/src/main/java/clientserver/Client.java
deleted file mode 100644
index 98bd287..0000000
--- a/app/src/main/java/clientserver/Client.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package clientserver;
-
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-
-public class Client {
- public static void main(String[] args) {
- try {
- // 1 - Création du canal avec un port libre
- DatagramSocket socketClient = new DatagramSocket();
- InetAddress adresseClient = InetAddress.getByName("localhost");
- byte[] envoyees; // tampon d'émission
- byte[] recues = new byte[1024]; // tampon de réception
- // 2 - Émettre
- String message = "hello serveur RX302";
- envoyees = message.getBytes();
- DatagramPacket messageEnvoye = new DatagramPacket(envoyees, envoyees.length, adresseClient, 6666);
- socketClient.send(messageEnvoye);
- // 3 - Recevoir
- DatagramPacket paquetRecu = new DatagramPacket(recues, recues.length);
- socketClient.receive(paquetRecu);
- String reponse = new String(paquetRecu.getData(), 0, paquetRecu.getLength());
- System.out.println(reponse + " @" + paquetRecu.getAddress() + ":" + paquetRecu.getPort());
- // 4 - Libérer le canal
- socketClient.close();
- } catch (Exception e) {
- System.err.println(e);
- }
- }
-}
diff --git a/app/src/main/java/clientserver/Server.java b/app/src/main/java/clientserver/Server.java
deleted file mode 100644
index 71ca9db..0000000
--- a/app/src/main/java/clientserver/Server.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package clientserver;
-
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-
-public class Server {
- static void scannerUDP(int startPort, int endPort) {
- try {
- for (int i = startPort; i < endPort; i++) {
- try (DatagramSocket socket = new DatagramSocket(i)) {
- } catch (Exception e) {
- System.out.println("Port n°" + i + " déjà occupé");
- }
- }
- } catch (Exception e) {
- System.out.println(e);
- }
- }
-
- public static void main(String[] args) {
- try {
- // 1 - Création du canal
- DatagramSocket socketServeur = new DatagramSocket(null);
- // 2 - Réservation du port
- InetSocketAddress adresse = new InetSocketAddress("localhost", 6666);
- socketServeur.bind(adresse);
- byte[] recues = new byte[1024]; // tampon d'émission
- byte[] envoyees; // tampon de réception
- // 3 - Recevoir
- DatagramPacket paquetRecu = new DatagramPacket(recues, recues.length);
- socketServeur.receive(paquetRecu);
- InetAddress adrClient = paquetRecu.getAddress();
- int prtClient = paquetRecu.getPort();
- System.out.println("Nouveau client : @" + adrClient + ":" + prtClient);
- // 4 - Émettre
- String reponse = "Serveur RX302 ready";
- envoyees = reponse.getBytes();
- DatagramPacket paquetEnvoye = new DatagramPacket(envoyees, envoyees.length, adrClient, prtClient);
- socketServeur.send(paquetEnvoye);
- // 5 - Libérer le canal
- socketServeur.close();
- } catch (Exception e) {
- System.err.println(e);
- }
- }
-}
diff --git a/app/src/main/java/clientserver/client/Client.java b/app/src/main/java/clientserver/client/Client.java
new file mode 100644
index 0000000..05f65d2
--- /dev/null
+++ b/app/src/main/java/clientserver/client/Client.java
@@ -0,0 +1,89 @@
+package clientserver.client;
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.util.concurrent.TimeUnit;
+
+public class Client {
+
+ InetAddress clientAddress;
+ int clientPort;
+
+ public void setPort(int port) {
+ this.clientPort = port;
+ }
+
+ public int getPort() {
+ return this.clientPort;
+ }
+
+ public InetAddress getAddress() {
+ return this.clientAddress;
+ }
+
+ public Client(InetAddress address, int port) {
+ this.clientAddress = address;
+ this.clientPort = port;
+ }
+
+ public static void main(String[] args) {
+ try {
+ // 1 - Création du canal avec un port libre
+ DatagramSocket socketClient = new DatagramSocket();
+ InetAddress serverAddress = InetAddress.getByName("localhost");
+ int serverPort = 6666;
+
+ // 2 - Envoyer un message au serveur
+ String message = "Connection request";
+ byte[] sendData = message.getBytes();
+ DatagramPacket sendPacket = new DatagramPacket(
+ sendData,
+ sendData.length,
+ serverAddress,
+ serverPort
+ );
+ socketClient.send(sendPacket);
+ System.out.println("New connection request sent");
+
+ // 3 - Recevoir
+ byte[] receivedData = new byte[1024]; // tampon de réception
+ DatagramPacket receivedPacket = new DatagramPacket(
+ receivedData,
+ receivedData.length
+ );
+ socketClient.receive(receivedPacket);
+ String reponse = new String(
+ receivedPacket.getData(),
+ 0,
+ receivedPacket.getLength()
+ );
+
+ if (reponse.startsWith("PORT:")) {
+ int newPort = Integer.parseInt(reponse.substring(5));
+
+ System.out.println("Connected on port:" + newPort);
+
+ // 4 - Communiquer sur le nouveau port
+ for (int i = 0; i < 20; i++) {
+ String messagePort = "Test";
+ byte[] envoyeesPort = messagePort.getBytes();
+ DatagramPacket paquetPort = new DatagramPacket(
+ envoyeesPort,
+ envoyeesPort.length,
+ serverAddress,
+ newPort
+ );
+ socketClient.send(paquetPort);
+ System.out.println("Test sent");
+ TimeUnit.SECONDS.sleep(1);
+ }
+ }
+
+ // 5 - Libérer le canal
+ socketClient.close();
+ } catch (Exception e) {
+ System.err.println(e);
+ }
+ }
+}
diff --git a/app/src/main/java/clientserver/MistralDirectAPI.java b/app/src/main/java/clientserver/common/MistralDirectAPI.java
similarity index 94%
rename from app/src/main/java/clientserver/MistralDirectAPI.java
rename to app/src/main/java/clientserver/common/MistralDirectAPI.java
index c1615e6..65bc0bc 100644
--- a/app/src/main/java/clientserver/MistralDirectAPI.java
+++ b/app/src/main/java/clientserver/common/MistralDirectAPI.java
@@ -1,11 +1,11 @@
-package clientserver;
+package clientserver.common;
+import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
-import java.io.FileInputStream;
import java.util.Properties;
public class MistralDirectAPI {
@@ -30,7 +30,7 @@ public class MistralDirectAPI {
{
"model": "mistral-medium",
"messages": [
- { "role": "user", "content": "Explain recursion like I'm five." }
+ { "role": "user", "content": "Reverse turing test." }
]
}
""";
diff --git a/app/src/main/java/clientserver/server/ClientHandler.java b/app/src/main/java/clientserver/server/ClientHandler.java
new file mode 100644
index 0000000..7d959a1
--- /dev/null
+++ b/app/src/main/java/clientserver/server/ClientHandler.java
@@ -0,0 +1,74 @@
+package clientserver.server;
+
+import clientserver.client.Client;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+
+public class ClientHandler implements Runnable {
+
+ private final DatagramSocket socket;
+ private final Client client;
+ private boolean running = true;
+
+ public ClientHandler(DatagramSocket socket, Client client) {
+ this.socket = socket;
+ this.client = client;
+ }
+
+ public void stop() {
+ running = false;
+ if (socket != null && !socket.isClosed()) {
+ socket.close();
+ }
+ }
+
+ @Override
+ public void run() {
+ System.out.println(
+ "Started handler for client " +
+ client.getAddress() +
+ ":" +
+ client.getPort()
+ );
+
+ // try {
+ // socket.setSoTimeout(30000);
+ // } catch (Exception e) {
+ // System.err.println("Could not set socket timeout");
+ // }
+
+ while (running && !socket.isClosed()) {
+ DatagramPacket packet = Server.receivedPacket(socket);
+ if (packet == null) continue;
+
+ String message = new String(
+ packet.getData(),
+ 0,
+ packet.getLength()
+ );
+ System.out.println(
+ "Received from " +
+ client.getAddress() +
+ ":" +
+ client.getPort() +
+ ": " +
+ message
+ );
+ // Reply with echo
+ // String response = "ECHO: " + message;
+ // Server.sendMessage(
+ // socket,
+ // response,
+ // client.getAddress(),
+ // client.getPort()
+ // );
+ }
+
+ System.out.println(
+ "Client handler terminated for " +
+ client.getAddress() +
+ ":" +
+ client.getPort()
+ );
+ }
+}
diff --git a/app/src/main/java/clientserver/server/Server.java b/app/src/main/java/clientserver/server/Server.java
new file mode 100644
index 0000000..ef2f21d
--- /dev/null
+++ b/app/src/main/java/clientserver/server/Server.java
@@ -0,0 +1,140 @@
+package clientserver.server;
+
+import clientserver.client.Client;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+
+public class Server {
+
+ private int mainServerPort;
+ private DatagramSocket mainServerSocket;
+ private boolean isRunning;
+
+ public Server(int port) {
+ this.mainServerPort = port;
+ mainServerSocket = createSocket(this.mainServerPort);
+ isRunning = true;
+ }
+
+ private DatagramSocket createSocket(int port) {
+ try {
+ return new DatagramSocket(port);
+ } catch (Exception e) {
+ System.err.println("Failed to bind server socket on port " + port);
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private DatagramSocket createNewSocket() {
+ try {
+ return new DatagramSocket(); // Reserve a random port
+ } catch (Exception e) {
+ System.err.println("Failed to create new server socket");
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static DatagramPacket receivedPacket(DatagramSocket socket) {
+ byte[] receivedData = new byte[1024];
+ DatagramPacket receivedPacket = new DatagramPacket(
+ receivedData,
+ receivedData.length
+ );
+
+ try {
+ socket.receive(receivedPacket); // Blocking call
+ return receivedPacket;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static void sendMessage(
+ DatagramSocket socket,
+ String message,
+ java.net.InetAddress address,
+ int port
+ ) {
+ try {
+ byte[] sendData = message.getBytes();
+ DatagramPacket packetToSend = new DatagramPacket(
+ sendData,
+ sendData.length,
+ address,
+ port
+ );
+ socket.send(packetToSend);
+ } catch (IOException e) {
+ System.err.println(
+ "Failed to send message to " + address + ":" + port
+ );
+ e.printStackTrace();
+ }
+ }
+
+ private void handleNewConnection() {
+ DatagramPacket packet = receivedPacket(mainServerSocket);
+ if (packet == null) return;
+
+ Client client = new Client(packet.getAddress(), packet.getPort());
+
+ // Log the initial connection request
+ System.out.println(
+ "New connection request from " +
+ client.getAddress() +
+ ":" +
+ client.getPort()
+ );
+
+ // Process the received message
+ String message = new String(packet.getData(), 0, packet.getLength());
+ System.out.println(
+ "Received message from " +
+ client.getAddress() +
+ ":" +
+ client.getPort() +
+ ": " +
+ message
+ );
+
+ // Create a new socket for this client
+ DatagramSocket clientSocket = createNewSocket();
+ if (clientSocket == null) return;
+
+ int newPort = clientSocket.getLocalPort();
+ client.setPort(newPort);
+
+ // Send new port information to client
+ String response = "PORT:" + newPort;
+ sendMessage(
+ mainServerSocket,
+ response,
+ client.getAddress(),
+ packet.getPort()
+ );
+
+ // Create and start a ClientHandler for this connection
+ ClientHandler handler = new ClientHandler(clientSocket, client);
+ Thread thread = new Thread(handler);
+ thread.start();
+ }
+
+ public void run() {
+ System.out.println("Server started on port " + mainServerPort);
+ while (isRunning) {
+ try {
+ handleNewConnection();
+ } catch (Exception e) {
+ System.err.println(
+ "Error handling connection: " + e.getMessage()
+ );
+ e.printStackTrace();
+ }
+ }
+ System.out.println("Server shutdown");
+ }
+}