feat: refactor client and added a receive thread, possibility to chat with server via client handler
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
package clientserver.client;
|
package clientserver.client;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramPacket;
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import clientserver.server.Server;
|
import clientserver.server.Server;
|
||||||
|
|
||||||
@@ -17,6 +17,56 @@ public class Client {
|
|||||||
private InetAddress serverAddress;
|
private InetAddress serverAddress;
|
||||||
private int serverPort;
|
private int serverPort;
|
||||||
private String pseudo;
|
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) {
|
public void setPort(int port) {
|
||||||
this.clientPort = port;
|
this.clientPort = port;
|
||||||
@@ -50,30 +100,50 @@ public class Client {
|
|||||||
this.pseudo = pseudo;
|
this.pseudo = pseudo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Client(InetAddress address, int port) {
|
public Scanner getScanner() {
|
||||||
this.clientAddress = address;
|
return this.scan;
|
||||||
this.clientPort = port;
|
}
|
||||||
|
|
||||||
|
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) {
|
public static Client createAndConfigureClient(DatagramSocket socketClient) {
|
||||||
Scanner scan = new Scanner(System.in);
|
|
||||||
System.out.println("Enter your Pseudo :");
|
System.out.println("Enter your Pseudo :");
|
||||||
String userPseudo = scan.next();
|
|
||||||
|
|
||||||
// Créer le client avec l'adresse locale et le port du socket
|
// 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.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 :");
|
System.out.println("Enter the IP address of the server :");
|
||||||
try {
|
try {
|
||||||
client.serverAddress = InetAddress.getByName(scan.next());
|
client.serverAddress = InetAddress.getByName(client.getScanner().next());
|
||||||
} catch (UnknownHostException e) {
|
} 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 :");
|
System.out.println("Enter the port of the server:");
|
||||||
client.setServerPort(scan.nextInt());
|
client.setServerPort(client.getScanner().nextInt());
|
||||||
scan.close();
|
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) {
|
if (socketClient != null && client.serverAddress != null) {
|
||||||
Server.sendMessage(socketClient, client.getPseudo(), client.serverAddress, client.getServerPort());
|
Server.sendMessage(socketClient, client.getPseudo(), client.serverAddress, client.getServerPort());
|
||||||
@@ -93,76 +163,80 @@ public class Client {
|
|||||||
client.getServerAddress(),
|
client.getServerAddress(),
|
||||||
handlerPort);
|
handlerPort);
|
||||||
socketClient.send(disconnectPacket);
|
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) {
|
} 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) {
|
public static void main(String[] args) {
|
||||||
try {
|
try {
|
||||||
DatagramSocket socketClient = null;
|
// 1 - Création du canal avec un port libre
|
||||||
try {
|
DatagramSocket socketClient = new DatagramSocket();
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2 - Création du client avec l'envoi du pseudo pour l'établissement de la
|
// 2 - Création du client avec l'envoi du pseudo pour l'établissement de la
|
||||||
// connexion avec le server
|
// connexion
|
||||||
Client client = createAndConfigureClient(socketClient);
|
Client client = createAndConfigureClient(socketClient);
|
||||||
|
|
||||||
// // 3 - Recevoir
|
// 3 - Recevoir la réponse initiale du serveur
|
||||||
DatagramPacket receivedPacket = Server.receivedPacket(socketClient);
|
DatagramPacket receivedPacket = Server.receivedPacket(socketClient);
|
||||||
String reponse = Server.packetToMessage(receivedPacket);
|
String reponse = Server.packetToMessage(receivedPacket);
|
||||||
|
|
||||||
if (reponse.startsWith("PORT:")) {
|
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
|
// 4 - Lancer uniquement le thread de réception des messages
|
||||||
for (int i = 0; i < 3; i++) {
|
MessageReceiver receiver = new MessageReceiver(socketClient);
|
||||||
String messagePort = "Test";
|
Thread receiverThread = new Thread(receiver);
|
||||||
byte[] envoyeesPort = messagePort.getBytes();
|
receiverThread.setDaemon(true);
|
||||||
DatagramPacket paquetPort = new DatagramPacket(
|
receiverThread.start();
|
||||||
envoyeesPort,
|
|
||||||
envoyeesPort.length,
|
|
||||||
client.getServerAddress(),
|
|
||||||
newClientHandlerPort);
|
|
||||||
socketClient.send(paquetPort);
|
|
||||||
System.out.println("Test sent");
|
|
||||||
|
|
||||||
try {
|
// 5 - Éxecution du client, bloquant tant que le client est connecté.
|
||||||
// Définir un timeout court pour que la boucle continue
|
client.run();
|
||||||
socketClient.setSoTimeout(1000);
|
|
||||||
|
|
||||||
byte[] reponseData = new byte[1024];
|
// 6 - Arrêter le thread de réception
|
||||||
DatagramPacket reponsePacket = new DatagramPacket(
|
receiver.stop();
|
||||||
reponseData,
|
try {
|
||||||
reponseData.length);
|
receiverThread.join(1000);
|
||||||
socketClient.receive(reponsePacket);
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
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();
|
socketClient.close();
|
||||||
|
System.out.println("Client closed");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println(e);
|
System.err.println(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,15 @@ public class ClientHandler implements Runnable {
|
|||||||
this.client = client;
|
this.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendConnectedClients() {
|
private void sendConnectedClients(String message) {
|
||||||
Server.sendMessage(clientHandlerSocket, Server.getPseudos(), client.getAddress(), client.getPort());
|
if (message.equals("/list")) {
|
||||||
|
Server.sendMessage(clientHandlerSocket, Server.getPseudos(), client.getAddress(), client.getPort());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDeconnexion(String message) {
|
private void handleDeconnexion(String message) {
|
||||||
if (message.equals("DISCONNECT")) {
|
if (message.equals("DISCONNECT")) {
|
||||||
System.out.println("Déconnexion du client : " + client.getPseudo());
|
System.out.println("Client deconnection : " + prettyPrint(client));
|
||||||
Server.removeClientHandler(client.getPseudo());
|
Server.removeClientHandler(client.getPseudo());
|
||||||
stop();
|
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
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
System.out.println(
|
System.out.println(
|
||||||
"Started handler for client " +
|
"Started handler for client " +
|
||||||
client.getAddress() +
|
prettyPrint(client));
|
||||||
":" +
|
|
||||||
client.getPort());
|
|
||||||
|
|
||||||
while (running && !clientHandlerSocket.isClosed()) {
|
while (running && !clientHandlerSocket.isClosed()) {
|
||||||
DatagramPacket packet = Server.receivedPacket(clientHandlerSocket);
|
DatagramPacket packet = Server.receivedPacket(clientHandlerSocket);
|
||||||
@@ -52,21 +63,16 @@ public class ClientHandler implements Runnable {
|
|||||||
0,
|
0,
|
||||||
packet.getLength());
|
packet.getLength());
|
||||||
System.out.println(
|
System.out.println(
|
||||||
"Received from " +
|
prettyPrint(client) + " : " +
|
||||||
client.getAddress() +
|
|
||||||
":" +
|
|
||||||
client.getPort() +
|
|
||||||
": " +
|
|
||||||
message);
|
message);
|
||||||
|
|
||||||
sendConnectedClients();
|
// Possibilies
|
||||||
handleDeconnexion(message);
|
sendConnectedClients(message); // /list command
|
||||||
|
handleDeconnexion(message); // exit command or DISCONNECT
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println(
|
System.out.println(
|
||||||
"Client handler terminated for " +
|
"Client handler terminated for " +
|
||||||
client.getAddress() +
|
prettyPrint(client));
|
||||||
":" +
|
|
||||||
client.getPort());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user