Chat en java
Chapi
-
KX Messages postés 16761 Date d'inscription Statut Modérateur Dernière intervention -
KX Messages postés 16761 Date d'inscription Statut Modérateur Dernière intervention -
Bonjour,
Je dois réaliser un chat pour un TP mais je suis bloqué. Lorsqu'un client se déconnecte, plus rien ne fonctionne et je n'arrive pas à savoir d'où cela provient.
Voici les messages d'erreur qui s'affiche pour le Client lorsqu'il se déconnecte :
Erreur au run : java.net.SocketException: Socket closed
Et voici celui du Serveur :
Erreur au run : java.net.SocketException: Software caused connection abort: socket write error
Voici le code du Client :
Et voici celui du Serveur :
Merci d'avance pour votre aide !
Je dois réaliser un chat pour un TP mais je suis bloqué. Lorsqu'un client se déconnecte, plus rien ne fonctionne et je n'arrive pas à savoir d'où cela provient.
Voici les messages d'erreur qui s'affiche pour le Client lorsqu'il se déconnecte :
Erreur au run : java.net.SocketException: Socket closed
Et voici celui du Serveur :
Erreur au run : java.net.SocketException: Software caused connection abort: socket write error
Voici le code du Client :
package chat; /* **** Chat multiclient - M1-Informatique ***** * Client.java * */ // Packages a inclure import java.io.*; import java.net.*; import java.util.Scanner; import java.util.logging.Level; import java.util.logging.Logger; public class Client implements Runnable { // Declaration des attributs de la classe // private int port; private InetAddress inetAddress; Thread _t; Socket s; String login; // Les methodes /** * Constructeur de la classe Client */ public Client() { } /** * Methode declenchee automatiquement apres l'execution de '_t.start()', son * role est de lire et afficher les messages envoyes par le serveur */ //Il s'agit des messages envoyes par les autres utilisateurs (clients) */ public void run() { try { while (true) { // 1. Recuperer le flux d'entree du socket s (methode getInputStream() de la classe Socket) InputStream is = s.getInputStream(); ObjectInputStream ois = new ObjectInputStream(is); // 2. Lire le message envoye par le serveur (Il faut utiliser une methode bloquante, par exemple : readObject()) Object obj = ois.readObject(); // 3. Convertir l'objet lu ('Object') en une chaine de caracteres ('String') String msg = (String) obj; // 4. Afficher la chaine de caracteres System.out.println(msg); } } catch (Exception e) { System.out.println("Erreur au run : " + e); } } /** * Methode permettant de lire une chaine de caracteres depuis la ligne de * commandes */ public String readMessage() throws IOException { String s = ""; char c; while ((c = (char) System.in.read()) != '\n') { if (c != '\r') { s = s + c; } } return s; } /** * Methode permettant de se connecter au serveur, de lire les chaines de * caracteres depuis une ligne de commandes, puis de les envoyer au serveur. * La chaine 'Bye' doit mettre fin a la connexion */ public void launch() { try { String msg = ""; // 1. Creer le socket System.out.println("Connexion au serveur..."); s = new Socket(getInetAddress(), getPort()); // 2. Lancer le Thread (methode 'start') permettant de recevoir les reponses du serveur _t = new Thread(this); _t.start(); OutputStream os = s.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject((Object) login); while (!(msg.equals("Bye"))) { // 3. Recuperer le flux de sortie du socket (methode getOutputStream() de la classe Socket) Scanner sc = new Scanner(System.in); msg = sc.nextLine(); // 4. Ecrire le message sur le flux de sortie du socket (methode writeObject()); oos.writeObject((Object) msg); } // 5. Mettre fin a la connexion si le message envoye est 'Bye' s.close(); } catch (IOException e) { System.out.println("Erreur de sérialisation " + e); } } /** * Methode permettant d'introduire le numero de port utilise par le serveur */ public void setPort(int _port) { port = _port; } /** * Methode permettant de retourner le numero de port du serveur */ public int getPort() { return port; } /** * Methode permettant d'introduire le nom ou l'IP du serveur */ public void setInetAddress(String _machineName) { try { inetAddress = InetAddress.getByName(_machineName); } catch (UnknownHostException ex) { System.out.println("Impossible de lire le nom ou l'adresse IP du serveur."); } } /** * Methode permettant de retourner l'adresse IP du serveur */ public InetAddress getInetAddress() { return inetAddress; } /** * Methode permettant d'introduire le login de l'utilisateur */ public void setLogin() { Scanner sc_login = new Scanner(System.in); System.out.println("Entrez votre login : "); login = sc_login.nextLine(); } ////////////////////////////////////////////////////////////////////////////////////////////// // Methode principale : 'main' // // Le programme prendra 2 parametres : une adresse ou un nom de serveur et un numero de port. // ////////////////////////////////////////////////////////////////////////////////////////////// public static void main(String arg[]) { Client em = new Client(); em.setInetAddress(arg[0]); em.setPort(Integer.parseInt(arg[1])); em.setLogin(); em.launch(); } }
Et voici celui du Serveur :
package chat; /* **** Chat multiclient - M1-Informatique ***** * Server.java * */ // Packages a inclure import java.net.*; import java.io.*; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class Server implements Runnable { // Declaration des attributs de la classe private int listenPort; private ServerSocket ss; private Thread _t; Socket _s; Vector clients = new Vector(); // Declaration des methodes /** * Constructeur de la classe Server */ public Server() throws IOException { } /** * Methode permettant d'introduire le numero de port du serveur */ private void setListenPort(int _listenPort) { listenPort = _listenPort; } /** * Methode permettant de retourner le numero de port du serveur */ public int getPort() { return listenPort; } /** * Methode permettant de lancer le serveur */ private void launch() { try { // 1. Creer le ServerSocket : ServerSocket(int _port) ss = new ServerSocket(listenPort); } catch (IOException ex) { System.out.println("Erreur : " + ex); } System.out.println("Serveur en execution..."); try { while (true) { // 2. Appeler la methode 'accept()' du ServerSocket creee en 1. _s = ss.accept(); // 3. Ajouter la nouvelle connexion dans un vecteur (ou tableau) contenant toutes les connexions. clients.add(_s); // 4. Appeler la methode _t.start() permettant de lancer run() (run() : permet de traiter les connexions des clients) _t = new Thread(this); _t.start(); } } catch (Exception e) { System.out.println("Erreur socket ...." + e); System.exit(0); } } public void run() { try { // 1. Recuperer le dernier socket du vecteur (ou tableau) Socket st = (Socket) clients.lastElement(); // 2. Recuperer le flux d'entree du socket (methode getInputStream() de la classe Socket) InputStream is = st.getInputStream(); // 3. Lire le premier message envoye par le client (en utilisant une methode bloquante, par exemple : readObject()). Il s'agit du login de l'utilisateur. ObjectInputStream ois = new ObjectInputStream(is); String login = (String) ois.readObject(); // 4. Imprimer le message System.out.println("Connexion de " + login + "."); while (true) { // 5. Lire le message envoye par le client (methode bloquante) String message = (String) ois.readObject(); // 6. Imprimer le message System.out.println(login + " : " + message); // 7. Envoyer le message lu a tous les autres clients, le preceder par le login de l'utilisateur concerne if (!clients.isEmpty()) { for (Object client : clients) { Socket sck = (Socket) client; OutputStream os = sck.getOutputStream(); // Utilisation de getOutputStream() et writeObject. ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(login + " : " + message); } } if(message.equals("Bye")) { clients.remove(st); } } } catch (IOException | ClassNotFoundException e) { System.out.println("Erreur au run : " + e); } } ////////////////////////////////////////////////////////////////////////////////////////////// // Methode principale : 'main' // // Le programme prendra 1 parametre : le numero de port a surveiller // ////////////////////////////////////////////////////////////////////////////////////////////// public static void main(String arg[]) { try { Server server = new Server(); int port = Integer.parseInt(arg[0]); server.setListenPort(port); server.launch(); } catch (IOException ex) { Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex); } } }
Merci d'avance pour votre aide !
A voir également:
- Chat en java
- Coco chat - Accueil - Réseaux sociaux
- Remplaçant de Coco : quelles solutions pour tchater gratuitement en ligne ? - Accueil - Réseaux sociaux
- Waptrick java football - Télécharger - Jeux vidéo
- Jeux java itel - Télécharger - Jeux vidéo
- Chat engine - Télécharger - Outils Internet
1 réponse
Bonsoir,
Pour avoir plus de détails sur l'exception tu dois afficher la trace complète de l'exception et non te limiter à son message. De plus évites le System.exit(0), surtout pour un erreur, à la rigueur un System.exit(1), mais en pratique on préférera propager l'exception comme ceci par exemple :
Ça te permettra de savoir d'où vient l'erreur, en l'occurrence ici :
En effet, comme tu l'as indiqué : la méthode est bloquante, donc si le client s'arrête abruptement le serveur ne peut plus le traiter. Mais dans ce cas il ne faudra pas que le serveur plante, c'est un comportement attendu que le client se déconnecte.
Pour avoir plus de détails sur l'exception tu dois afficher la trace complète de l'exception et non te limiter à son message. De plus évites le System.exit(0), surtout pour un erreur, à la rigueur un System.exit(1), mais en pratique on préférera propager l'exception comme ceci par exemple :
} catch (Exception e) { throw new RuntimeException("Erreur au run", e); }
Ça te permettra de savoir d'où vient l'erreur, en l'occurrence ici :
// 5. Lire le message envoye par le client (methode bloquante) String message = (String) ois.readObject();
En effet, comme tu l'as indiqué : la méthode est bloquante, donc si le client s'arrête abruptement le serveur ne peut plus le traiter. Mais dans ce cas il ne faudra pas que le serveur plante, c'est un comportement attendu que le client se déconnecte.
Malheureusement, je ne vois toujours pas comment résoudre la situation.
Exemple :
Remarque : je trouve le choix de l'ObjectInputStream maladroit. Ce que tu lis ici ce sont des String, donc à la rigueur on utilise OIS, mais avec un readUTF8 à la place de readObject, mais je pense qu'il est préférable d'utiliser un flux texte de type Scanner, ce qui te permettrait de détecter la fin du flux et ne pas avoir d'erreur dans ce cas, par exemple en faisant un
Remarque : les RuntimeException et toutes ses classes filles ont l'avantage de ne pas avoir à être try/catché, mais cela implique aussi qu'un code qui n'a pas besoin d'être try/catché peut quand même lever une RuntimeException. C'est pour ça qu'il est préférable de catcher assez large, j'ai donc remplacé par mais on aurait pu faire aussi . Quelques exemples de RuntimeException bien connus : NullPointerException ou IndexOutOfBoundException...
En essayant votre exemple, le terminal me retourne une erreur "NullPointerException". Voilà ce que j'ai fait dans le code pour obtenir ce résultat :
Concernant l'utilisation de scanner, ce programme est à réaliser dans le cadre d'un TP et je ne sais pas du tout si j'ai le droit ou non d'utiliser autre chose que ce qu'il m'est indiqué de faire.
Je pense que l'erreur vient du client, car quelque soit les modifications dans Serveur, cela ne fonctionne pas. Je ne peux même pas être sûr de cela, cependant.
Je vous remercie encore de bien vouloir m'aider, j'ai vraiment du mal avec ce programme et cela me décourage malheureusement beaucoup.
Il faut faire cela dans l'autre sens.
Les conditions sont évaluées de gauche à droite (sauf les dernières si elles ne servent à rien)
Du coup, ça plante sur le parce qu'il n'a pas encore vu que .
Il faut donc tester la valeur null en premier.
Il ne cherchera pas à faire le puisque c'est un OU alors que la première condition vaut true, il sait déjà que le résultat final est true, peu importe la deuxième condition (qui plante).
J'ai obtenu un autre message d'erreur que j'ai résolue en remplaçant le vector clients par un arraylist, le serveur marche maintenant sans problème !
J'ai cependant un dernier soucis avec mon client. En effet, j'ai toujours le message d'erreur : "
Caused by: java.net.SocketException: Socket closed" à cause de la ligne 43, soit
Je suppose qu'il faut que j'effectue une démarche similaire à celle effectué dans Serveur. Je vous remercie encore pour votre aide !