diff --git a/app/src/main/java/clientserver/client/Client.java b/app/src/main/java/clientserver/client/Client.java index 6793d91..0c381c3 100644 --- a/app/src/main/java/clientserver/client/Client.java +++ b/app/src/main/java/clientserver/client/Client.java @@ -1,5 +1,6 @@ package clientserver.client; +import clientserver.server.Server; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; @@ -8,8 +9,6 @@ import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.Scanner; -import clientserver.server.Server; - public class Client { InetAddress clientAddress; @@ -27,6 +26,7 @@ public class Client { } private static class MessageReceiver implements Runnable { + private final DatagramSocket socket; private volatile boolean running = true; @@ -38,26 +38,32 @@ public class Client { public void run() { try { socket.setSoTimeout(500); // Petit timeout pour pouvoir vérifier régulièrement si on doit s'arrêter, - // evite thread zombie car receive() est bloquant + // evite thread zombie car receive() est bloquant while (running && !socket.isClosed()) { try { byte[] buffer = new byte[1024]; - DatagramPacket packet = new DatagramPacket(buffer, buffer.length); + DatagramPacket packet = new DatagramPacket( + buffer, + buffer.length + ); socket.receive(packet); - String message = new String(packet.getData(), 0, packet.getLength()); + String message = new String( + packet.getData(), + 0, + packet.getLength() + ); // Afficher le message reçu avec une mise en forme claire - System.out.println("\n>>> Message from server: \n" + message); - System.out.print("Enter your message (or 'exit' to quit): "); - } catch (SocketTimeoutException e) { - } + System.out.println(message); + } catch (SocketTimeoutException e) {} } - } catch (IOException e) { if (!socket.isClosed()) { - System.err.println("Error in the reception of messages: " + e.getMessage()); + System.err.println( + "Error in the reception of messages: " + e.getMessage() + ); } } System.out.println("Message receiver stopped"); @@ -128,16 +134,23 @@ public class Client { System.out.println("Enter your Pseudo :"); // Créer le client avec l'adresse locale et le port du socket - Client client = new Client(socketClient.getLocalAddress(), socketClient.getLocalPort()); + Client client = new Client( + socketClient.getLocalAddress(), + socketClient.getLocalPort() + ); client.setScanner(new Scanner(System.in)); String userPseudo = client.getScanner().next(); client.setPseudo(userPseudo); System.out.println("Enter the IP address of the server :"); try { - client.serverAddress = InetAddress.getByName(client.getScanner().next()); + client.serverAddress = InetAddress.getByName( + client.getScanner().next() + ); } catch (UnknownHostException e) { - System.err.println("The address you choose create an UnknownHostException: " + e); + System.err.println( + "The address you choose create an UnknownHostException: " + e + ); } System.out.println("Enter the port of the server:"); @@ -146,26 +159,40 @@ public class Client { // (morph (/127.0.0.1:39056) : ...) if (socketClient != null && client.serverAddress != null) { - Server.sendMessage(socketClient, client.getPseudo(), client.serverAddress, client.getServerPort()); + Server.sendMessage( + socketClient, + client.getPseudo(), + client.serverAddress, + client.getServerPort() + ); System.out.println("New connection request sent"); } return client; } - private static void deconnexionClient(DatagramSocket socketClient, Client client, int handlerPort) { + private static void deconnexionClient( + DatagramSocket socketClient, + Client client, + int handlerPort + ) { try { - String disconnectMsg = "DISCONNECT"; + String disconnectMsg = "/disconnect"; byte[] disconnectData = disconnectMsg.getBytes(); DatagramPacket disconnectPacket = new DatagramPacket( - disconnectData, - disconnectData.length, - client.getServerAddress(), - handlerPort); + disconnectData, + disconnectData.length, + client.getServerAddress(), + handlerPort + ); socketClient.send(disconnectPacket); - System.out.println("Deconnection sended on the server port: " + handlerPort); + System.out.println( + "Deconnection sended on the server port: " + handlerPort + ); } catch (Exception e) { - System.err.println("Error during sending the deconnection message: " + e); + System.err.println( + "Error during sending the deconnection message: " + e + ); } } @@ -174,18 +201,28 @@ public class Client { boolean running = true; System.out.println("\n=== Chat client ready ==="); - System.out.println("Type your messages then press 'Enter' to send them to the server."); + // System.out.println( + // "Type your messages then press 'Enter' to send them to the server." + // ); System.out.println("Type /list to see all the clients connected."); - System.out.println("Type 'exit' to quit."); + System.out.println( + "Type '/msg ' to send a private message." + ); + System.out.println("Type '/help' to see all the commands."); + System.out.println("Type '/disconnect' to quit.\n"); while (running) { - System.out.print("Enter your message: "); String message = this.getScanner().nextLine(); - if ("exit".equalsIgnoreCase(message)) { + if ("/disconnect".equalsIgnoreCase(message)) { running = false; } else { - Server.sendMessage(this.clientSocket, message, this.getServerAddress(), this.getHandlerPort()); + Server.sendMessage( + this.clientSocket, + message, + this.getServerAddress(), + this.getHandlerPort() + ); } } @@ -231,7 +268,9 @@ public class Client { Thread.currentThread().interrupt(); } } else { - System.err.println("Unexpected response from the server: " + reponse); + System.err.println( + "Unexpected response from the server: " + reponse + ); } // 8 - Libérer le canal diff --git a/app/src/main/java/clientserver/server/ClientHandler.java b/app/src/main/java/clientserver/server/ClientHandler.java index d54d337..bbd612b 100644 --- a/app/src/main/java/clientserver/server/ClientHandler.java +++ b/app/src/main/java/clientserver/server/ClientHandler.java @@ -21,6 +21,10 @@ public class ClientHandler implements Runnable { ); } + public Client getClient() { + return client; + } + public void stop() { running = false; if (clientHandlerSocket != null && !clientHandlerSocket.isClosed()) { diff --git a/app/src/main/java/clientserver/server/MessageProcessor.java b/app/src/main/java/clientserver/server/MessageProcessor.java index 73f7949..a61c416 100644 --- a/app/src/main/java/clientserver/server/MessageProcessor.java +++ b/app/src/main/java/clientserver/server/MessageProcessor.java @@ -1,7 +1,6 @@ package clientserver.server; import clientserver.client.Client; -import java.net.DatagramPacket; import java.net.DatagramSocket; public class MessageProcessor { @@ -25,11 +24,84 @@ public class MessageProcessor { return; } - if (message.equals("/list")) { - handleListCommand(); - } else if (message.equals("DISCONNECT")) { - handleDisconnect(); + if (message.startsWith("/msg ")) { + handlePrivateMessage(message); + return; } + + switch (message) { + case "/list": + handleListCommand(); + break; + case "/help": + handleHelpCommand(); + break; + case "/msg": + handleMsgCommand(); + break; + case "/disconnect": + handleDisconnect(); + break; + } + } + + private void handlePrivateMessage(String message) { + String[] parts = message.split(" ", 3); + if (parts.length < 3) { + handleMsgCommand(); + return; + } + + String targetPseudo = parts[1]; + String messageContent = parts[2]; + + ClientHandler targetHandler = Server.getClientHandler(targetPseudo); + + if (targetHandler == null) { + Server.sendMessage( + clientHandlerSocket, + "> User " + targetPseudo + " not found", + client.getAddress(), + client.getPort() + ); + return; + } + + // Send private message to target + Client targetClient = targetHandler.getClient(); + Server.sendMessage( + clientHandlerSocket, + "> " + + client.getPseudo() + + " -> " + + targetClient.getPseudo() + + ": " + + messageContent, + targetClient.getAddress(), + targetClient.getPort() + ); + + // Send confirmation to sender + Server.sendMessage( + clientHandlerSocket, + "> " + + client.getPseudo() + + " -> " + + targetClient.getPseudo() + + ": " + + messageContent, + client.getAddress(), + client.getPort() + ); + } + + private void handleMsgCommand() { + Server.sendMessage( + clientHandlerSocket, + "> /msg : send a message to a client", + client.getAddress(), + client.getPort() + ); } private void handleListCommand() { @@ -41,6 +113,17 @@ public class MessageProcessor { ); } + private void handleHelpCommand() { + Server.sendMessage( + clientHandlerSocket, + "> /list : list all connected clients" + + "\n> /msg : send a message to a client" + + "\n> /disconnect : disconnect from the server", + client.getAddress(), + client.getPort() + ); + } + private void handleDisconnect() { System.out.println( "Client deconnection : " + ClientHandler.prettyPrint(client) diff --git a/app/src/main/java/clientserver/server/Server.java b/app/src/main/java/clientserver/server/Server.java index 5a8b192..22721ee 100644 --- a/app/src/main/java/clientserver/server/Server.java +++ b/app/src/main/java/clientserver/server/Server.java @@ -13,7 +13,10 @@ public class Server { private int mainServerPort; private DatagramSocket mainServerSocket; private boolean isRunning; - private static Map mapPseudosConnectedClientsHandlers = new ConcurrentHashMap<>(); + private static Map< + String, + ClientHandler + > mapPseudosConnectedClientsHandlers = new ConcurrentHashMap<>(); public Server(int port) { this.mainServerPort = port; @@ -44,8 +47,9 @@ public class Server { public static DatagramPacket receivedPacket(DatagramSocket socket) { byte[] receivedData = new byte[1024]; DatagramPacket receivedPacket = new DatagramPacket( - receivedData, - receivedData.length); + receivedData, + receivedData.length + ); try { socket.receive(receivedPacket); // Blocking call @@ -57,81 +61,84 @@ public class Server { } public static String packetToMessage(DatagramPacket packet) { - return new String( - packet.getData(), - 0, - packet.getLength()); + return new String(packet.getData(), 0, packet.getLength()); } public static void sendMessage( - DatagramSocket socket, - String message, - java.net.InetAddress address, - int port) { + DatagramSocket socket, + String message, + java.net.InetAddress address, + int port + ) { try { byte[] sendData = message.getBytes(); DatagramPacket packetToSend = new DatagramPacket( - sendData, - sendData.length, - address, - port); + sendData, + sendData.length, + address, + port + ); socket.send(packetToSend); } catch (IOException e) { System.err.println( - "Failed to send message to " + address + ":" + port); + "Failed to send message to " + address + ":" + port + ); e.printStackTrace(); } } private void handleNewConnection() { DatagramPacket packet = receivedPacket(mainServerSocket); - if (packet == null) - return; + if (packet == null) return; int originalClientPort = packet.getPort(); InetAddress clientAddress = packet.getAddress(); - ; - // Log the initial connection request System.out.println( - "New connection request from " + - clientAddress + - ":" + - originalClientPort); + "New connection request from " + + clientAddress + + ":" + + originalClientPort + ); // Process the received message - String pseudoMessage = new String(packet.getData(), 0, packet.getLength()); - System.out.println( - "Received message from " + - clientAddress + - ":" + - originalClientPort + - ": " + - pseudoMessage); + String pseudoMessage = new String( + packet.getData(), + 0, + packet.getLength() + ); + System.out.println( + "Received message from " + + clientAddress + + ":" + + originalClientPort + + ": " + + pseudoMessage + ); // Create a new socket for this client DatagramSocket clientHandlerSocket = createNewSocket(); - if (clientHandlerSocket == null) - return; + if (clientHandlerSocket == null) return; int clientHandlerLocalPort = clientHandlerSocket.getLocalPort(); Client client = new Client(clientAddress, originalClientPort); - client.setPseudo(pseudoMessage); + client.setPseudo(pseudoMessage); // Send new port information to client String response = "PORT:" + clientHandlerLocalPort; - sendMessage( - mainServerSocket, - response, - clientAddress, - packet.getPort()); + sendMessage( + mainServerSocket, + response, + clientAddress, + packet.getPort() + ); // Create and start a ClientHandler for this connection ClientHandler handler = new ClientHandler(clientHandlerSocket, client); + Thread thread = new Thread(handler); thread.start(); - // Add client handler to mapPseudosConnectedClients addConnectedClientHandler(pseudoMessage, handler); } @@ -143,7 +150,8 @@ public class Server { handleNewConnection(); } catch (Exception e) { System.err.println( - "Error handling connection: " + e.getMessage()); + "Error handling connection: " + e.getMessage() + ); e.printStackTrace(); } } @@ -151,12 +159,30 @@ public class Server { } public static String getPseudos() { - StringBuilder pseudos = new StringBuilder("All connected clients:\n"); - mapPseudosConnectedClientsHandlers.forEach((k, v) -> pseudos.append("Pseudo: ").append(k).append("\n")); + StringBuilder pseudos = new StringBuilder(); + int size = mapPseudosConnectedClientsHandlers.size(); + int count = 0; + for (Map.Entry< + String, + ClientHandler + > entry : mapPseudosConnectedClientsHandlers.entrySet()) { + count++; + pseudos.append("> ").append(entry.getKey()); + if (count < size) { + pseudos.append("\n"); + } + } return pseudos.toString(); } - public void addConnectedClientHandler(String pseudo, ClientHandler clientHandler) { + public static ClientHandler getClientHandler(String pseudo) { + return mapPseudosConnectedClientsHandlers.get(pseudo); + } + + public void addConnectedClientHandler( + String pseudo, + ClientHandler clientHandler + ) { mapPseudosConnectedClientsHandlers.putIfAbsent(pseudo, clientHandler); } diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..336465c --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +org.gradle.console=plain