Probleme Socket et ObjectInputStream [Résolu]

Messages postés
16
Date d'inscription
mercredi 17 mars 2010
Dernière intervention
10 janvier 2012
- - Dernière réponse : slifeur22
Messages postés
16
Date d'inscription
mercredi 17 mars 2010
Dernière intervention
10 janvier 2012
- 27 juin 2011 à 20:01
Bonjour tout le monde, je vais essayer d'etre bref, j'essaie de faire un programme en Java de messagerie instantané qui ressemble a 80% a MSN,en utilisant les interface graphique Swing et AWT ainsi que les Socket TCP

mon niveau en Java est intermediaire(je dirrai pas debutant ni expert quand meme)
voila le plan de mon projet (je serai heureux de vos suggestion pour l'améliorer ) :

- Serveur

[*] 1 - a la connexion du Server,il affiche une fenetre JFrame qui contient une JList personalisé qui simule la liste des contacte, il se met en ecoute sur un port avec la ServerSocket.accept() avec un Thread pour lui permettre de faire autre chose que l'ecoute...
[*] dès la connexion d'un Client, j'instancie une classe ServerClient dont les attributs sont (Socket :retourné avec accept() et String Pseudo envoyé par le client quand il s'est connecté) et fait deux chose :
[*] Ajouter l'objet ServerClient a la JList du Server
[*] Envoyer le nouveau Client Client connecté a tous les Socket des ServerClient se trouvant sur cette JList (afin d'informer les clients déjà connecté de la connexion d'un nouveau membre).

vu que le Serveur et le Client peuvent recevoir plusieurs données a un instant T, et ces données ont besoin d’être traité selon leur nature, j'ai jugé plus convenable de créer un Objet que je nommerai transmission qui contient deux attribut (String indicateur et Object donnée) , l'indicateur pour indiquer la nature de l'objet reçu afin de le traiter comme il se doit, et donnée ça peut être n'importe quoi (Vector, String, int, POJO), après des teste j'arrive un problème c'est que lors de la réception le Client n'est pas bloqué lors du "input.readObject()" et il continue sont chemin en boucle ce qui me génère pas mal d'Exception. Autre chose, j'aimerai gérer la fermeture des Socket lors de la déconnexion d'un client ou même du Serveur entier, pour plus d'information voila mon code teste , j'ai omis de mettre le projet principale avec les JFrame et tout car c'est beaucoup lourd (14 CLASS), j'ai crée un nouveau projet pour test :

Dans ce test le client est en ecoute permanante avec le Thread monOperation, le Serveur quant a lui il envoi deux objet, une chaine String, et un Vector, le Client reçoit les deux et les traite comme il se doit, CEPENDANT il doit se remettre en écoute encore mais c'est pas le cas, MERCI d'avance les gars

Class Client
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class Client {	
public static void main(String[] args) throws Exception{
Socket socket = new Socket("localhost",12345);
// l'objet qur recevera les données
Transmission t = null;		
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
// le Thread qui s'occupe de la reception et traitement selon la nature
monOperation Mo = new monOperation(input, t);		
}
}


Class Serveur
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import javax.swing.JOptionPane;

public class Serveur {	
public static void main(String[] args)throws Exception{		
ServerSocket serveur = new ServerSocket(12345);
Socket socket = serveur.accept();
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());		
// saisir une donnée quelconque
String msg = JOptionPane.showInputDialog(null, "Ecrire votre Message : ");
Transmission t = new Transmission("Message", msg);
// envoyé la chaine saisi
output.writeObject(t);
output.flush();
// creation d'un vector pr tester
Vector x = new Vector();
x.add("Bonjour");
x.add(88);

t = new Transmission("Tableau", x);	
output.writeObject(t);		
output.flush();		
// je sais pas encore quand est ce que je dois fermer la Socket
}
}


Class Transmission : l'objet a transmettre
import java.io.Serializable;
public class Transmission implements Serializable {

private static final long serialVersionUID = 1L;
private String indicateur;
private Object Donnee;
// Constructeur
public Transmission(String i,Object d){	indicateur i;	Donnee d;	}
// getter
public String getIndicateur() {	return indicateur;}
public Object getDonnee() {return Donnee;}
// setter
public void setIndicateur(String indicateur) {this.indicateur = indicateur;}
public void setDonnee(Object donnee) {Donnee = donnee;}	

}


class monOperation : Thread de reception permanante
import java.io.ObjectInputStream;
import java.util.Vector;


public class monOperation extends Thread{

private ObjectInputStream input;
private Transmission transmission;

public monOperation(ObjectInputStream i,Transmission t){
input = i;
transmission = t;
start();
}

public void run(){
try {
// on recuper l'objet  (c'est là où ça se bloque pas !!)
Transmission trans = (Transmission) input.readObject();
String indicateur = "";
// connaitre la nature de l'objet recu
indicateur = trans.getIndicateur();

if(indicateur.equals("Message")){
// traitement pour Message
String msg = (String) trans.getDonnee();
System.out.println("Recu du Serveur : "+ msg);

}else if(indicateur.equals("Tableau")){
// traitement pour les tableau
Vector x = (Vector) trans.getDonnee();
System.out.println("Recu du Serveur : "+ x);

}else{
// traitement par defaut si on reconnait pas 
System.out.println("Object non reconnu");
}
} catch (Exception e) {
e.printStackTrace();
}		
// pour assurer la repetition du Thread (si vous avez d'autre suggestion n'hesitez pas)
new monOperation(input, transmission);
}


}
Afficher la suite 

Votre réponse

13 réponses

Meilleure réponse
Messages postés
6450
Date d'inscription
mardi 8 mars 2005
Dernière intervention
17 mai 2018
3
Merci
Oui, j'ai compris pourquoi ton programme ne s'arrêtait pas, c'est que tu créé la nouvelle instance en dehors du bloc try, elle est donc exécutée qu'il y ait une erreur ou non.

Pour assurer la répétition du thread, tu peux faire ceci :

public void run(){
try {
while(true){
Transmission trans = (Transmission) input.readObject();
String indicateur = "";
// connaitre la nature de l'objet recu
indicateur = trans.getIndicateur();

if(indicateur.equals("Message")){
// traitement pour Message
String msg = (String) trans.getDonnee();
System.out.println("Recu du Serveur : "+ msg);
}
else if(indicateur.equals("Tableau")){
// traitement pour les tableau
Vector x = (Vector) trans.getDonnee();
System.out.println("Recu du Serveur : "+ x);
}
else{
// traitement par defaut si on reconnait pas 
System.out.println("Object non reconnu");
}
}
}
catch (Exception e) {
e.printStackTrace();
}		
}

Merci cs_Julien39 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources a aidé 97 internautes ce mois-ci

Commenter la réponse de cs_Julien39
Messages postés
6450
Date d'inscription
mardi 8 mars 2005
Dernière intervention
17 mai 2018
0
Merci
Une main avec un throws Exception est une très très
mauvaise idée. De manière générale, essayes de mieux gérer tes exceptions : Regarde MSN par exemple, quand on n'arrive pas à se connecter, il ne nous affiche pas une erreur système.

Au lieu de faire un catch(Exception e) systématiquement, catch les exceptions qui sont réellement susceptibles d'être levées et trouve une solution adaptée à chaque type d'exception et propage la si tu ne trouves pas de solution immédiatement (mais catch là quand même et lève une nouvelle exception éventuellement une exception perso)

Ton codes est bien commenté mais utilise la javadoc /** */ de facon normalisée : regarde sur le site du zero, c'est bien expliqué. Les commentaires // sont utilisés pour bloquer du code et les /* */ insèrent des commentaires dans le code.

Respectes les normes d'écriture en java : les constructeurs sur une seule ligne choquent.

Tu peux utiliser des énums au lieu des String Message, Tableau...


Je te fais une classe exemple (juste pour la normalisation du code)

import java.io.Serializable;
/**
  * Transmission est la classe qui...
  * 
  * Une Transmission est caracterisee par les inforamtions suivantes :
  * 
  * <li>Un indicateur</li>
  * <li>Des donnees</li>
  * 
  * 


  * 
  * De plus, une Transmission permet de...
  * 


  *
  * @see les classes auxquelles se referer
  *
  * @author tonNom
  * @version 1.0
  */
public class Transmission implements Serializable {

private static final long serialVersionUID = 1L;

        /**
          * Description
          */
private String indicateur;

        /**
          * Description
          */
private Object donnee;

        /**
          * Constructeur de Transmission
          * @param i
          *        L'indicateur
          * @param d
          *        Les donnees
          */
public Transmission(String i, Object d){
                indicateur = i;
                donnee = d;
        }

        /**
          * Accesseur à l'indicateur
          * @return l'indicateur
          */
public String getIndicateur() {
                return indicateur;
        }

public Object getDonnee() {
                return Donnee;
        }

public void setIndicateur(String indicateur) {
                this.indicateur = indicateur;
        }

public void setDonnee(Object donnee) {
                this.donnee=donnee;
        }	

}


Voilà essayes d'être plus précis que moi sur les commentaires, l'exemple te montre plus la forme que le fond.

Les noms d'attributs commencent toujours pas une minuscule.


Voilà tout, sinon, c'est assez propre
Commenter la réponse de cs_Julien39
Messages postés
16
Date d'inscription
mercredi 17 mars 2010
Dernière intervention
10 janvier 2012
0
Merci
Merci pour les conseil julien39 j'y tiendrai compte la prochaine fois, si tu veux je peux réécrire les 4 classe en tenant compte des norme de commentaire, en ce concerne le constructeur et même les getters et setters j'ai essayé de réduire le nombre de ligne afin de pouvoir le poster sur le forum sinon ça contient des trentaine de ligne sur Eclipse, même chose pour Exception au lieu de faire IOException et ClassNotFoundException , par contre si vous avez exécuté le code est ce que tu as une idée pourquoi le processus ne se bloque pas lors de "input.readObject()" ?, pour éclaircir voila ce qui se passe : a la première itération (Récursive) le input.readObject() reçoit le "Message" et il le traite OK, a la deuxième il reçoit le "Tableau" et il le traite OK, mais à la 3éme itération il reçoit rien et il doit rester en attente normalement, mais il attend environ une Seconde ou deux avant de déclencher l'Exception et ça se répète dans la boucle récursive, sinon je peux mettre mon code Source non Compressé qui contient plein de sysout pour Journalisée l’exécution et savoir où ça plante exactement (en tenant compte des norme des commentaire cette fois ).
By the way : j'ai pas compris ce que vous vouliez dire par utiliser des enum au lieu de indicateur : String
Commenter la réponse de slifeur22
Messages postés
6450
Date d'inscription
mardi 8 mars 2005
Dernière intervention
17 mai 2018
0
Merci
Tu peux réécrire tes classes en respectant les normes de codage, mais ne les repostes pas, celles que tu as écrit sont très lisibles. Mais si tu veux améliorer la qualité de ton code, tu devrais les réécrire.

Tu peux créer un enum de la facon suivante :

public enum NomEnum {
     Message,
     Tableau
     ;
}


Et utiliser des .valueOf et des .name() pour passer de String à NomEnum. Mais, c'est a voir en fonction des besoins de ton application, en général, j'essaye de ne pas écrire trop de String en dur dans le code.


Et au sujet des exceptions, le problème principal est le fait qu'elles ne soient pas gérées : un printStackTrace n'est pas une information que recevra l'utilisateur.

Pour ton erreur, je ne vois pas ce qui ne va pas et je n'ai pas exécuté le code
Commenter la réponse de cs_Julien39
Messages postés
16
Date d'inscription
mercredi 17 mars 2010
Dernière intervention
10 janvier 2012
0
Merci
merci pour l'enum, je vais essayé avec c'est mieux structuré a ce que je vois, si tu comprends bien l'utilité de mon Objet Transmission,ça presente l'unité a envoyé entre le Serveur et le Client,l'indicateur sert a reconnaitre le traitement associé a cette transmission, les donnée quant a elle, ce sont les donnée a recevoir et a traiter selon l'indicateur, par pour la gestion de l'exception j'ai laissé le trackTrace pour vous, j'avais mis un message d'erreur genre "probleme lors de recuperation du flux d'entre", mais ça m'affiche en boucle ce message
Commenter la réponse de slifeur22
Messages postés
6450
Date d'inscription
mardi 8 mars 2005
Dernière intervention
17 mai 2018
0
Merci
Dans ce cas là, le programme boucle tant qu'il n'y a pas d'erreur
Commenter la réponse de cs_Julien39
Messages postés
6450
Date d'inscription
mardi 8 mars 2005
Dernière intervention
17 mai 2018
0
Merci
Et pour ta première question, oui, tu dois fermer le socket.
Commenter la réponse de cs_Julien39
Messages postés
16
Date d'inscription
mercredi 17 mars 2010
Dernière intervention
10 janvier 2012
0
Merci
Bonsoir, Merci pour la remarque , j'avais pas fait attention et j'avais pas pensé a faire une boucle a l'interieur du try (j'en avait mis une englobant le tout mais je l'ai enlevé), ça a limité l'erreur et déclenchement infini de l'exception suite a l'erreur précédente, par contre , ma connexion est rompue juste après la réception du 2éme objet et le readObject déclenche une IOException du type : Connection reset alors que théoriquement il doit être bloqué meme si le client n'envoi plus rien, est ce qu'il y a une erreur dans mon code ou il c'est du au langage et au Garbage collector qui détruit tout ce qu'on a plus besoin d'utiliser?

PS1 : j'ai tenu en compte les standard des commentaires comme tu l'as remarqué
PS2: j'ai aussi géré les exception au lieu de mettre throws pour s'en debarasser des bloc try/catch
PS3: est ce qu'en marquant le sujet résolu on aura tjrs le droit d’écrire et répondre?

import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Vector;


public class monOperation extends Thread{
/** le flux d'entree */
private ObjectInputStream input;
/** L'objet qui sera traité apres reception */
private Transmission transmission;

/** Constructeur a parametre */
public monOperation(ObjectInputStream i,Transmission t){
input = i;
transmission = t;
start();
}

public void run(){
/** un indice pour m'afficher je suis dans quel iteration*/
int i=0;
try {

while(true){
System.out.println(++i);
/** on recuper l'objet  (c'est là où ça se bloque pas !!) */
Transmission trans = (Transmission) input.readObject();
String indicateur = "";
/** connaitre la nature de l'objet recu */
indicateur = trans.getIndicateur();

if(indicateur.equals("Message")){

/** traitement pour Message */
String msg = (String) trans.getDonnee();
System.out.println("Recu du Serveur : "+ msg);

}else if(indicateur.equals("Tableau")){
/** traitement pour les tableau */
Vector x = (Vector) trans.getDonnee();
System.out.println("Recu du Serveur : "+ x);

}else{
/** traitement par defaut si on reconnait pas*/ 
System.out.println("Object non reconnu");
}
}

} 
catch (IOException e) {
System.err.println("IOexception declancé : "+e.getMessage());		
}		
/** pour assurer la repetition du Thread (si vous avez d'autre suggestion n'hesitez pas) */
//new monOperation(input, transmission);
catch (ClassNotFoundException e) {

// TODO Auto-generated catch block
System.err.println("Class non Reconnu"+e.getMessage());
}
}

}



Resultat :

1
Recu du Serveur : coucou
2
Recu du Serveur : [Bonjour, 88]
3
IOexception declancé : Connection reset
Commenter la réponse de slifeur22
Messages postés
6450
Date d'inscription
mardi 8 mars 2005
Dernière intervention
17 mai 2018
0
Merci
Je ne vois pas bien d'où vient ton problème, en tout cas ce n'est pas le garbage collector, tu aurais une nullPointerException sinon.

Au sujet de la forme, les commentaires qui ne sont pas de la javadoc ne se mettent qu'avec une * : /* ; La javadoc se trouve au dessus des fonctions de facon normalisée comme je te l'ai montré plus haut. De plus, une nouvelle instruction commence à la ligne donc le }else if(indicateur... s'écrit en fait:
}
else if(indicateur.equals("Tableau")){

Mais ce n'est pas primordial.

Tu risques une nullPointerException sur cette ligne indicateur = trans.getIndicateur();
Tu devrais la remplacer par :
if(trans!=null){
   indicateur = trans.getIndicateur();
}
Commenter la réponse de cs_Julien39
Messages postés
6450
Date d'inscription
mardi 8 mars 2005
Dernière intervention
17 mai 2018
0
Merci
Et oui, si tu acceptes la réponse, on pourra continuer de poster des messages.
Commenter la réponse de cs_Julien39
Messages postés
16
Date d'inscription
mercredi 17 mars 2010
Dernière intervention
10 janvier 2012
0
Merci
désolé pour le retard, voila j'ai accepté la réponse, et pour la fermeture de la Socket, comment vous proposer sa gestion? sachant que c le client qui vais se déconnecter, soit en déclenchant "Socket.close()" , soit en tuant le thread Main principale du client
Commenter la réponse de slifeur22
Messages postés
6450
Date d'inscription
mardi 8 mars 2005
Dernière intervention
17 mai 2018
0
Merci
L'idéal c'est de le fermer après 10 minutes d'inactivité.
Commenter la réponse de cs_Julien39
Messages postés
16
Date d'inscription
mercredi 17 mars 2010
Dernière intervention
10 janvier 2012
0
Merci
je veux pas un temps d'inactivité, je veux moi meme gerer la fermeture de socket et la deconnexion des clients, par exemple si un client clique sur "X" pour fermer la fenetre, ou il clique sur le MenuItem "Quitter", je veux signaler au serveur que ce client vient de se deconnecter et automatiquement ce dernier va le supprimer de la liste de contact et informe tous les autres client deja connecté de le supprimer
Commenter la réponse de slifeur22

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.