diff --git a/app/src/main/java/clientserver/client/Client.java b/app/src/main/java/clientserver/client/Client.java index 5186eeb..6793d91 100644 --- a/app/src/main/java/clientserver/client/Client.java +++ b/app/src/main/java/clientserver/client/Client.java @@ -1,12 +1,12 @@ package clientserver.client; +import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; -import java.net.SocketException; +import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.Scanner; -import java.util.concurrent.TimeUnit; import clientserver.server.Server; @@ -17,6 +17,56 @@ public class Client { private InetAddress serverAddress; private int serverPort; private String pseudo; + private Scanner scan; + private DatagramSocket clientSocket; + private int handlerPort; + + public Client(InetAddress address, int port) { + this.clientAddress = address; + this.clientPort = port; + } + + private static class MessageReceiver implements Runnable { + private final DatagramSocket socket; + private volatile boolean running = true; + + public MessageReceiver(DatagramSocket socket) { + this.socket = socket; + } + + @Override + 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 + + while (running && !socket.isClosed()) { + try { + byte[] buffer = new byte[1024]; + DatagramPacket packet = new DatagramPacket(buffer, buffer.length); + + socket.receive(packet); + 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) { + } + } + + } catch (IOException e) { + if (!socket.isClosed()) { + System.err.println("Error in the reception of messages: " + e.getMessage()); + } + } + System.out.println("Message receiver stopped"); + } + + public void stop() { + running = false; + } + } public void setPort(int port) { this.clientPort = port; @@ -50,30 +100,50 @@ public class Client { this.pseudo = pseudo; } - public Client(InetAddress address, int port) { - this.clientAddress = address; - this.clientPort = port; + public Scanner getScanner() { + return this.scan; + } + + public void setScanner(Scanner scan) { + this.scan = scan; + } + + public DatagramSocket getClientSocket() { + return this.clientSocket; + } + + public void setClientSocket(DatagramSocket clientSocket) { + this.clientSocket = clientSocket; + } + + public int getHandlerPort() { + return handlerPort; + } + + public void setHandlerPort(int handlerPort) { + this.handlerPort = handlerPort; } public static Client createAndConfigureClient(DatagramSocket socketClient) { - Scanner scan = new Scanner(System.in); System.out.println("Enter your Pseudo :"); - String userPseudo = scan.next(); // Créer le client avec l'adresse locale et le port du socket Client client = new Client(socketClient.getLocalAddress(), socketClient.getLocalPort()); - client.pseudo = userPseudo; + 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(scan.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 :"); - client.setServerPort(scan.nextInt()); - scan.close(); + System.out.println("Enter the port of the server:"); + client.setServerPort(client.getScanner().nextInt()); + client.getScanner().nextLine(); // Consume the remaining newline to avoid sending a void line message like + // (morph (/127.0.0.1:39056) : ...) if (socketClient != null && client.serverAddress != null) { Server.sendMessage(socketClient, client.getPseudo(), client.serverAddress, client.getServerPort()); @@ -93,76 +163,80 @@ public class Client { client.getServerAddress(), handlerPort); socketClient.send(disconnectPacket); - System.out.println("Déconnexion envoyée au serveur sur le port " + handlerPort); + System.out.println("Deconnection sended on the server port: " + handlerPort); } catch (Exception e) { - System.err.println("Erreur lors de l'envoi du message de déconnexion : " + e); + System.err.println("Error during sending the deconnection message: " + e); } } + public void run() { + // 1 - Boucle principale pour l'envoi des messages + 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 /list to see all the clients connected."); + System.out.println("Type 'exit' to quit."); + + while (running) { + System.out.print("Enter your message: "); + String message = this.getScanner().nextLine(); + + if ("exit".equalsIgnoreCase(message)) { + running = false; + } else { + Server.sendMessage(this.clientSocket, message, this.getServerAddress(), this.getHandlerPort()); + } + } + + // 2 - Gérer la déconnexion proprement + System.out.println("Deconnection in progress..."); + deconnexionClient(this.getClientSocket(), this, this.getHandlerPort()); + } + public static void main(String[] args) { try { - DatagramSocket socketClient = null; - try { - // 1 - Création du canal avec un port libre - socketClient = new DatagramSocket(); - } catch (SocketException e) { - System.err.println("The client socket cannot be created : " + e); - return; - } + // 1 - Création du canal avec un port libre + DatagramSocket socketClient = new DatagramSocket(); // 2 - Création du client avec l'envoi du pseudo pour l'établissement de la - // connexion avec le server + // connexion Client client = createAndConfigureClient(socketClient); - // // 3 - Recevoir + // 3 - Recevoir la réponse initiale du serveur DatagramPacket receivedPacket = Server.receivedPacket(socketClient); String reponse = Server.packetToMessage(receivedPacket); if (reponse.startsWith("PORT:")) { - int newClientHandlerPort = Integer.parseInt(reponse.substring(5)); + int handlerPort = Integer.parseInt(reponse.substring(5)); + System.out.println("Connected on handler port: " + handlerPort); - System.out.println("Connected on port:" + newClientHandlerPort); + client.setClientSocket(socketClient); + client.setHandlerPort(handlerPort); - // 4 - Communiquer sur le nouveau port - for (int i = 0; i < 3; i++) { - String messagePort = "Test"; - byte[] envoyeesPort = messagePort.getBytes(); - DatagramPacket paquetPort = new DatagramPacket( - envoyeesPort, - envoyeesPort.length, - client.getServerAddress(), - newClientHandlerPort); - socketClient.send(paquetPort); - System.out.println("Test sent"); + // 4 - Lancer uniquement le thread de réception des messages + MessageReceiver receiver = new MessageReceiver(socketClient); + Thread receiverThread = new Thread(receiver); + receiverThread.setDaemon(true); + receiverThread.start(); - try { - // Définir un timeout court pour que la boucle continue - socketClient.setSoTimeout(1000); + // 5 - Éxecution du client, bloquant tant que le client est connecté. + client.run(); - byte[] reponseData = new byte[1024]; - DatagramPacket reponsePacket = new DatagramPacket( - reponseData, - reponseData.length); - socketClient.receive(reponsePacket); - - String messageServeur = new String( - reponsePacket.getData(), - 0, - reponsePacket.getLength()); - - System.out.println("Serveur répond: \n" + messageServeur); - } catch (java.net.SocketTimeoutException e) { - // Ignorer le timeout et continuer - System.out.println("Pas de réponse du serveur cette fois-ci"); - } - - TimeUnit.SECONDS.sleep(1); + // 6 - Arrêter le thread de réception + receiver.stop(); + try { + receiverThread.join(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } - deconnexionClient(socketClient, client, newClientHandlerPort); + } else { + System.err.println("Unexpected response from the server: " + reponse); } - // 5 - Libérer le canal + // 8 - Libérer le canal socketClient.close(); + System.out.println("Client closed"); } catch (Exception e) { System.err.println(e); } diff --git a/app/src/main/java/clientserver/server/ClientHandler.java b/app/src/main/java/clientserver/server/ClientHandler.java index 0453f12..aca2804 100644 --- a/app/src/main/java/clientserver/server/ClientHandler.java +++ b/app/src/main/java/clientserver/server/ClientHandler.java @@ -15,13 +15,15 @@ public class ClientHandler implements Runnable { this.client = client; } - private void sendConnectedClients() { - Server.sendMessage(clientHandlerSocket, Server.getPseudos(), client.getAddress(), client.getPort()); + private void sendConnectedClients(String message) { + if (message.equals("/list")) { + Server.sendMessage(clientHandlerSocket, Server.getPseudos(), client.getAddress(), client.getPort()); + } } private void handleDeconnexion(String message) { if (message.equals("DISCONNECT")) { - System.out.println("Déconnexion du client : " + client.getPseudo()); + System.out.println("Client deconnection : " + prettyPrint(client)); Server.removeClientHandler(client.getPseudo()); stop(); } @@ -34,13 +36,22 @@ public class ClientHandler implements Runnable { } } + public String prettyPrint(Client client) { + StringBuilder str = new StringBuilder(); + str.append(client.getPseudo() + + " (" + + client.getAddress() + + ":" + + client.getPort() + + ")"); + return str.toString(); + } + @Override public void run() { System.out.println( "Started handler for client " + - client.getAddress() + - ":" + - client.getPort()); + prettyPrint(client)); while (running && !clientHandlerSocket.isClosed()) { DatagramPacket packet = Server.receivedPacket(clientHandlerSocket); @@ -52,21 +63,16 @@ public class ClientHandler implements Runnable { 0, packet.getLength()); System.out.println( - "Received from " + - client.getAddress() + - ":" + - client.getPort() + - ": " + + prettyPrint(client) + " : " + message); - sendConnectedClients(); - handleDeconnexion(message); + // Possibilies + sendConnectedClients(message); // /list command + handleDeconnexion(message); // exit command or DISCONNECT } System.out.println( "Client handler terminated for " + - client.getAddress() + - ":" + - client.getPort()); + prettyPrint(client)); } }