Se connecter avec
S'enregistrer | Connectez-vous

Serveur de messagerie Java.

Dernière réponse : dans Programmation

Bonjour,

J'ai réalisé dans le cadre d'un futur projet un serveur de messagerie instantanée en Java à l'aide des sockets.

Cependant, une chose qui marche et que je ne comprends pas :

- Au début, je me connectais au serveur via Telnet/Putty, puis j'ai fait un client graphique pour que ce soit plus joli etc.

Du point de vue serveur, je fais au départ :

  1. sortieSurClient = recupererSortieClient();
  2. entreeSurClient = recupererEntreeClient();
  3.  
  4. public PrintWriter recupererSortieClient() {
  5. try {
  6. return new PrintWriter (socketClient.getOutputStream());
  7. } catch (IOException e) {
  8. e.printStackTrace();
  9. }
  10. return null;
  11. }
  12.  
  13. public BufferedReader recupererEntreeClient() {
  14. try {
  15. return new BufferedReader(new InputStreamReader(socketClient.getInputStream()));
  16. } catch (IOException e1) {
  17. e1.printStackTrace();
  18. }
  19. return null;
  20. }

Puis ensuite, je récupère la saisie du client sur le .getInputStream().readLine() (en gros). Or, du point de vue client, lorsque j'écris sur ma socket, j'écris sur le .getOutputStream et je lis aussi sur le InputSteram().readLine()....

En gros, je ne comprends pas pourquoi du point de vue serveur, on écrit pas sur le flux d'entrée de la socket au lieu d'écrire sur la sortie. Pourquoi c'est le même sens pour les deux ?

Est-ce que ça voudrait dire que la socket que le serveur accepte (accept()), et celle crée dans le client que je connecte au serveur (new SOcket (localhost, 2011)) n'est pas la même ? Car pour moi, si c'est la même, les objets retournés par .getOutputStream et .getInput(...) sont les mêmes.

Merci :) 

Autres pages sur : serveur messagerie java

Lassé par la pub ? Créez un compte
Expert Programmation

Une socket c'est comme un tuyau. Chacun envoie dans le tuyau pour envoyer les données à l'autre (chacun voit le tuyau de son point de vue).

Ensuite, il y a un mécanisme qui ne se voit pas : c'est la création du socket côté serveur. Le client se connecte au serveur sur un port serveur Pserv avec son port PClient. Lorsque la connexion est acceptée, le serveur crée implicitement une nouvelle socket sur un port temporaire PServTemp côté serveur (car il faut libérer le port PServ pour toute autre nouvelle connexion). Au final, tu as une connexion entre le client (port PClient) et le serveur (port PServTemp), le serveur, ayant l'autre socket de connexion PServ en attente.

Merci pour ta réponse CRicky.

Donc si j'ai bien compris, une fois que j'ai créé ma socket côté serveur (new ServerSocket ("localhost", 2011), je lance le thread en attente de connexion qui écoute donc sur le port 2011.

Une fois qu'il intercepte une connexion, il accepte la socket, sauf que cette fois, il utilise un nouveau port (par exemple le 8048) pour dialoguer avec la socket client, au lieu de continuer à utiliser le port 2011, c'est ça ? (qu'il laisse libre pour les autres accept()).

Donc au final, lorsque du point de vue client, je fais new Socket("localhost", 2011), je suis connecté au port 2011, puis accepté, et ensuite redirigé vers un autre port (mécanisme caché par le haut niveau), généré par la socket du serveur ?

À ce moment-là, je comprends mieux le mécanisme de l'étape de connexion. En revanche, la socket client semble toujours la même, donc les objets .getOutputStream() et Input sont toujours les mêmes des deux côtés ?

Car, par exemple, du point de vue du client : j'écris sur socket.getoutpustream.. lors de l'envoi d'un message, et pour en recueillir (logiquement du serveur), je lis sur socket.getInputStream().
Or, vu que le serveur utilise le même sens sur le même objet (la socket client), pour moi, le client ne lirait jamais rien et le serveur non plus, puirqu'ils écriraient tous deux sur .getOutputStream().

Voilà, merci pour les réponses :) 
Expert Programmation

Pour la création des sockets, c'est bien ça.

Pour les envois et réceptions de données, attention, ce ne sont pas les mêmes objets. La comparaison avec un tuyau n'est pas tout à fait exacte (ce n'est pas un Pipe comme on peut voir sur un unix-like). En fait, une socket c'est plus comme une prise avec une entrée et une sortie. La connexion elle-même est gérée par la pile IP qui ne sait pas vraiment où se trouve le destinataire (c'est pour ça qu'il n'y a pas d'objet virtuel représentant la connexion).
Donc, côté client tu as une prise avec une entrée et une sortie, et côté serveur, tu as une autre prise avec son entrée et sa sortie (chacun possède sa socket, et même plusieurs côté serveur). La connexion entre 2 sockets se fait comme un câble croisé RJ45, la sortie d'une socket est connectée à l'entrée de l'autre, et inversement.

Hmm, donc lorsque je fais : socketClient = socketServeur.accept(), la socketClient n'est pas le même objet que la socket client que je crée dans le client.
Mais lorsque j'écris sur la socketClient (côté serveur), la fonction println, va implicitement envoyer le message vers le InputStream de la socket (côté client).

Cette socket client (côté serveur), serait-ce la socket temporaire dont tu parlais ? (en prenant un autre port, pour libérer le port de connexion)

Au fait, j'ai regardé sur l'API, mais la méthode flush(), que fait-elle exactement, "Flushes the stream" :p 
Je sais juste qu'il faut le mettre si on veut que le message soit envoyé :p 

Est-ce que donc ce serait :

- sortieSocketClientCoteServeur.println(message) -> j'écris sur la sortie de ma socket client côté serveur ;
- ...flush() -> ce que j'ai écrit est retiré de la sortie de ma socket client, et envoyé vers le flux d'entrée de la "vraie" socket client (côté client)
? :p 

C'est un peu embrouillant de pas manipuler directement, comme on pourrait le faire en C :) 

Merci.
Expert Programmation

Dans ton serveur, socketClient est une socket du côté du serveur, et c'est effectivement la socket temporaire (d'ailleurs si tu lis son port avec GetLocalPort(), tu verras que le port est différent de celui de la socket d'écoute).
socketClient est connectée à la socket du client. En Java, la méthode à employer est le streaming. Par exemple, côté serveur, tu envoies un flux de donnée dans la socket de ton processus (socketClient) en utilisant le OutputStream. Et côté client, le processus recevra dans sa socket (avec probablement encore un numéro de port différent) les données dans l'InputStream.
Inversement, si c'est le client qui veut envoyer des données, il va utiliser le OutputStream de sa socket, et côté serveur, ce sera reçu dans l'InputStream de socketClient.

Pour le flush, c'est parce que tout n'est pas directement envoyé, c'est mis dans un buffer temporaire avant de tout envoyer. Le flush permet d'envoyer le contenu du buffer sur le réseau (ça vide le buffer).

L'avantage du streaming, c'est que tu peux y envoyer tout objet serialisable, en envoyer plusieurs sans se soucier de la structure du buffer (contrairement au C). Donc, en fait ça apporte une couche d'abstraction, qui facilite le travail si tu as des données complexes à envoyer (d'ailleurs, c'est comme pour l'écriture dans un fichier binaire).

D'accord, j'ai bien compris ce que tu m'as expliqué CriCKY.
Une socket client est crée du côté serveur (sur un autre port que celui d'écoute) lors d'une connexion d'un client. Celle-ci est connectée à la socket client (côté client).

La seule chose étrange, j'ai testé (côté serveur et client), ça me dit que le port local (côté serveur) est le 2011 (le même que pour l'écoute), et la même chose côté client (pour le port distant).

Peut-être est-ce à cause du haut niveau qui cache ça..

Merci pour les liens redsux que j'ai parcourus. Merci CriCky.
Maintenant, va falloir que je me penche sur les déconnexions, car y a pas mal d'exceptions :o 

Re,

Est-ce que je pourrais avoir un petit coup de main pour les déconnexion ? :) 
Lorsque je suis sur mon client (cmd ou java), j'arrive à me déconnecter. Je procède comme ceci : j'envoie le message exit sur le flux de sortie, ce qui fait ceci dans le Thread qui gère un client :

  1. public void detruireSession() {
  2. System.err.println("Session "+socketClient.getRemoteSocketAddress()+" détruite !");
  3. /*
  4. * On ferme les flux d'entrée/sortie sur le client distant.
  5. */
  6. try {
  7. entreeSurClient.close();
  8. } catch (IOException e) {
  9. e.printStackTrace();
  10. }
  11. sortieSurClient.close();
  12. for (int i=0; i<serveur.getListeClients().size(); i++) {
  13. if (serveur.getListeClients().get(i) == this)
  14. serveur.retirerClient(i);
  15. }
  16. /*
  17. * Si le pseudo n'a pas été défini, on ne déclare pas aux autres utilisateurs
  18. * que l'instance connectée a été déconnectée... et on ne le supprime pas
  19. * dans la liste des clients identifiés, puisqu'il n'y figure pas.
  20. */
  21. if (pseudo != null) {
  22. for (int i=0; i<serveur.getListeClientsIdentifies().size(); i++) {
  23. if (serveur.getListeClientsIdentifies().get(i) == this)
  24. serveur.retirerClientIdentifie(i);
  25. }
  26. posterMessage(pseudo+ " a quitte le serveur !", true);
  27. }
  28. /*
  29. * On ferme la socket client.
  30. */
  31. try {
  32. socketClient.close();
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. /*
  37. * On passe sessionActive à false pour que la boucle lireMessage() s'arrête.
  38. */
  39. sessionActive = false;
  40.  
  41. /*
  42. * On signale au garbage collector qu'il peut détruire le Thread.
  43. */
  44. try {
  45. this.finalize();
  46. } catch (Throwable e) {
  47. e.printStackTrace();
  48. }
  49. }

Puis sur mon client java, je fais ceci :

  1. public void terminer() {
  2. try {
  3. entreeSurServeur.close();
  4. } catch (IOException e1) {
  5. e1.printStackTrace();
  6. }
  7. sortieSurServeur.close();
  8. try {
  9. socket.close();
  10. } catch (IOException e) {
  11. e.printStackTrace();
  12. }
  13. }


Jusqu'ici, cela semble marcher .... mais lorsque j'essaie dans l'autre sens, c'est à dire de déconnecter un utilisateur (ou de fermer le serveur) à partir de la fenêtre graphique du serveur, j'ai des problèmes ....

Lorsque je souhaite déconnecter un client en particulier, je récupère son toString() à l'aide de la JList, et ensuite, je fais ceci :

  1. public void deconnecterUtilisateur (String utilisateur) {
  2. int i;
  3. for (i=0; !listeClients.get(i).toString().equals(utilisateur); i++) {}
  4. listeClients.get(i).detruireSession(); // méthode plus haut
  5. }


Et lorsque je fais "fermer serveur", je fais pareil pour toute la liste.
Le problème, c'est que ça ne marche pas dans ce sens-là :D 

Pourtant, j'ai bien le message "session détruite" de la méthode detruireSession, mais les messages parviennent toujours, ce qui amène à penser que la méthode detruireSession ne marche pas du tout ...

Encore plus "bizarre", quand je suis en console, il faut attendre que le client tape quelque chose sur sa console, et là il est déconnecté. Sur la console, il n'est pas déconnecté du tout, mais s'il envoie le message exit, il l'est bien .. je ne comprends pas :p 

Je pense que je n'ai pas bien saisi les mécanismes de déconnexion des sockets. Avez-vous une idée ?

Merci !
Expert Programmation

Bon, j'ai regardé une doc, et en fait je me suis trompé (ça fait longtemps que je ne suis pas rentré dans ce genre de détail :D  ), c'est bien une nouvelle socket qui est créée, mais le port ne change pas (tu auras 2 sockets sur ce port).
En fait, c'est parce qu'une socket est composé de:
- protocole (TCP ou UDP)
- adresse client
- port client
- adresse serveur
- port serveur
C'est l'ensemble de ces 5 infos qui différencies 2 sockets, donc le serveur peut avoir plusieurs socket sur le même port.

Donc, si tu as plusieurs client, le port local sera le même, mais pour identifier la socket, c'est le couple adresse client/port client qui fait la différence (c'est le protocole TCP qui gère ça, pas le protocole IP).

Hey,

D'accord.
Oui, on avait commencé à le faire en C il y a deux semaines, où j'ai aperçu qu'il y avait la configuration serveur et client (pour créer la socket et la connecter)

  1. /* On configure un type de socket (ipv4, tcp, 0)*/
  2. int sock = socket(PF_INET, SOCK_STREAM, 0);
  3.  
  4. /* On configure le serveur auquel on veut se connecter (adresse, port) */
  5. struct sockaddr_in serveur;
  6. serveur.sin_family = AF_INET;
  7. serveur.sin_port = htons(9);
  8. serveur.sin_addr.s_addr = inet_addr("192.168.0.22");
  9.  
  10. /* On configure le client pour faire le bind (non obligatoire) */
  11. struct sockaddr_in client;
  12. client.sin_family = AF_INET;
  13. client.sin_port = htons(2000);
  14. client.sin_addr.s_addr = inet_addr("192.168.0.22");
  15.  
  16. if (bind (sock, (struct sockaddr*)&client , sizeof(client)) < 0 )
  17. perror("configuration socket echouee");
  18.  
  19. printf ("bind fait \n");
  20. sleep(3);
  21.  
  22. // faire netstat -antp, et on voit les différences
  23.  
  24. /* On se connecte (configuraton automatique de la socket (adresse ip, port) */
  25. if (connect(sock, (struct sockaddr*)&serveur, sizeof(serveur))<0)
  26. perror("connection a échoué");
  27.  
  28. printf ("connect fait\n");
  29. sleep(3);
  30.  
  31. char msg[] = "Bonjour Ellie";
  32. /* On écrit "salut" sur la socket */
  33. write (sock, msg, sizeof(msg));
  34. close (sock);


Je suppose qu'en revanche, la ServerSocket est gérée différemment, puisque c'est bien fait pour l'écoute, et pas pour aller dans les deux sens.

Merci de l'information :) 

Je l'ai fait dans le client et le serveur, et effectivement, ça marche déjà beaucoup mieux =)

Curieux dans un sens, je pensais que ça faisait à peu près la même chose. Il reste quelques petits problèmes (semble qu'il y a une boucle qui tourne en rond dans le client java lors que je le déconnecte) que je vais essayer de régler !

Merci

Salut,

Je n'ai pas trouvé pourquoi, mais la méthode detruireSession() dans GestionClient est appelé deux fois à chaque fois que je décide de déconnecter un client (comme si y avait une récursivité ...), aussi bien quand je déconnecte un client que quand je choisis de fermer tout le serveur.

J'arrive aussi à avoir une erreur (que j'avais déjà avant) sur mon readLine() == null de mon Client (cette fois), qui me dit (lorsque j'ai fait "fermer le serveur"):

java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at modele.Client$1.run(Client.java:34)


D'autant plus bizarre que ces exceptions sont venues sur un seul des deux clients java connectés :p 

edit : trouvé le problème .. problème de synchronisation sur la liste des clients ... :p  maintenant, faut-il le régler =)
Problème résolu en inversant la boucle de fermer(), en partant de la fin de la liste jusqu'au début, comme ça pas de risque de se tromper (sinon la liste se met à jour) alors que la boucle est toujours en cours, donc des éléments passent à la trappe :p . En revanche, je n'ai toujours pas trouvé la solution pour le premier problèem.

Merci!

Re,

Et bien, en fait, j'ai toujours beaucoup d'exceptions lors des déconnexions.

Côté serveur: lorsque je déconnecte un client précis, la méthode detruireSession semble être appelée deux fois, je ne vois pas pourquoi ...
Côté client : ça l'air d'être le même problème...

Voulez-vous que je poste le code de ces parties ?

Alors, du point de vue serveur, lorsque je déconnecte un client :

  1. public void deconnecterUtilisateur (String utilisateur) {
  2. int i;
  3. for (i=0; !listeClients.get(i).toString().equals(utilisateur); i++) {}
  4. listeClients.get(i).detruireSession();
  5. }


  1. public void detruireSession() {
  2. System.err.println("Session "+socketClient.getRemoteSocketAddress()+" détruite !");
  3. /*
  4. * On passe sessionActive à false pour que la boucle lireMessage() s'arrête.
  5. */
  6. sessionActive = false;
  7. try {
  8. socketClient.shutdownInput();
  9. socketClient.shutdownOutput();
  10. } catch (IOException e1) {e1.printStackTrace();}
  11. /*
  12. * On ferme les flux d'entrée/sortie sur le client distant.
  13. */
  14. try {
  15. entreeSurClient.close();
  16. } catch (IOException e) {e.printStackTrace();}
  17.  
  18. sortieSurClient.close();
  19. Message message = new Message("retirerClient", "", this, null, "", true);
  20. serveur.getBoiteDeMessages().insererMessage(message);
  21. /*
  22. * Si le pseudo n'a pas été défini, on ne déclare pas aux autres utilisateurs
  23. * que l'instance connectée a été déconnectée... et on ne le supprime pas
  24. * dans la liste des clients identifiés, puisqu'il n'y figure pas.
  25. */
  26. if (pseudo != null) {
  27. Message message2 = new Message("retirerClientIdentifie", "", this, null, "", true);
  28. serveur.getBoiteDeMessages().insererMessage(message2);
  29. posterMessage(pseudo+ " a quitte le serveur !", true);
  30. }
  31. /*
  32. * On ferme la socket client.
  33. */
  34. try {
  35. socketClient.close();
  36. } catch (IOException e) {e.printStackTrace();}
  37. /*
  38. * On signale au garbage collector qu'il peut détruire le Thread.
  39. */
  40. try {
  41. this.finalize();
  42. } catch (Throwable e) {e.printStackTrace();}
  43. }

Il semblerait que cette étape se fasse deux fois, bizarrement...

----

J'ai de manière similaire le même problème lorsque mon client Java se déconnecte (si je clique sur bouton quitter) :

Citation :
java.net.SocketException: Socket input is already shutdown
at java.net.Socket.shutdownInput(Unknown Source)
at modele.Client.terminer(Client.java:74)
at modele.Client$1.run(Client.java:37)
java.net.SocketException: Socket is closed
at java.net.Socket.shutdownInput(Unknown Source)
at modele.Client.terminer(Client.java:74)
at modele.Client.quitterServeur(Client.java:89)
at vue.Panel.quitter(Panel.java:124)
at controleur.ControleurClient.actionPerformed(ControleurClient.java:25)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)


ou si je tape just "exit" dans mon client java :

Citation :
java.net.SocketException: Socket input is already shutdown
at java.net.Socket.shutdownInput(Unknown Source)
at modele.Client.terminer(Client.java:74)
at modele.Client$1.run(Client.java:37)


Note : La méthode quitterServeur() est appelée lorsque j'appuie sur le bouton quitter de la fenêtre.

et le code client pour la déconnexion :

  1. public void terminer() {
  2. fenetre.setConnexion(false);
  3. if (!reception.isInterrupted())
  4. reception.interrupt();
  5. try {
  6. socket.shutdownInput();
  7. socket.shutdownOutput();
  8. } catch (IOException e2) {e2.printStackTrace();}
  9. try {
  10. entreeSurServeur.close();
  11. } catch (IOException e1) {e1.printStackTrace();}
  12. sortieSurServeur.close();
  13. try {
  14. socket.close();
  15. } catch (IOException e) {e.printStackTrace();}
  16. }
  17.  
  18. public void quitterServeur() {
  19. reception.interrupt();
  20. envoyerMessage("exit", true);
  21. terminer();
  22. }
  23.  
  24. public void envoyerMessage (String message, boolean retour_charriot) {
  25. if (retour_charriot)
  26. sortieSurServeur.println(message);
  27. else
  28. sortieSurServeur.print(message);
  29. sortieSurServeur.flush();
  30. if (message.equals("exit")) {
  31. terminer();
  32. }
  33. }

terminer() est aussi appelé si readLine() == null.

Il semblerait donc qu'il y ait pour commencer de sproblèmes avec Readline().
Pourtant, je passe le booléen connexion à faux, lorsque je termine. La boucle readLine() est faite tant que connexion est vraie...

Je me demande donc si le problème (côté client Et côté serveur) ne se trouve pas du côté du ReadLine() qui rappelerait cette méthode terminer au moins une fois (de trop).
J'ai essayé le reception.interrupt() (qui interrompt le thread de réception (readline()) côté client, sans succès.

Merci

Re,

En fait, j'ai "arrangé" un peu le truc ... je sais pas si c'est très "propre".

J'ai mis des méthodes synchronized pour les déconnexions, en effectuant la déconnexion selon le booléen de connexion. Du coup, une seule déconnexion, donc plus de beug de ce côté.

Le seul truc étrange, c'est lorsque je ferme le client java directement par la petite croix, je pensais que ça allait faire un readLine() == null du côté serveur.. Mais là le serveur plante (uc 50 % ) :p  Pareil si je termine le processus directement par le gestionnaire des tâches ALORS que si je ferme par le croix ou par le gestionnaire des tâches "conhost.exe" (CMD avec un telnet sur le serveur port 2011), là ça roule.

Au début, je pensais faire un setDefaultCloseOperation(methodepourquitter()), mais évidemment, ça ne marche pas :p  Même si cela marchait, je trouve ça bizarre.

:) 

Bonjour,

Après quelque temps, j'ai passé l'application cliente en objet (qui utilise en flux d'entrée/sortie ObjectInputStream et ObjectOutputStream).. et ça fait un bout de temps que je galère sur un problème.

En fait, desfois, tout marche très bien, et desfois, ça plante...

J'envoie et reçois des objets avec les méthodes traditionnelles readObject() et writeObject(). Les objets que j'envoies implémentent bien Serializable() et ont le même serialVersionUID des deux côtés (client/serveur).

Or, j'ai souvent des exception du genre OptionalDataException, EOFException, j'ai bien-sûr regardé plusieurs fois les API's et lu les Api sur ces flux.. mais je ne comprends toujours pas pourquoi cela persiste à déconner sans raison apparente.

Le seul type d'objet que j'envoie est la liste des clients qui est affichée sous forme d'une JList chez le client. Pas de problème de ce côté là. Le problème se trouve bien avec les flux. Au début, j'avais remarqué que l'objet ne se mettait pas à jour (le writeObject() du serveur semblait renvoyer toujours le premier objet du même type envoyé à tel client). J'ai donc utilisé fluxSortie.reset() pour pallier à ce problème avant chaque write() ce qui est peut-être la cause de mes soucis.

J'ai bien essayé les méthodes writeUnshared() et readUnshared() qui sont censées justement ne pas faire référence au dernier objet envoyé, mais ça ne marchait même pas....

Le problème est donc, que desfois mes clients peuvent se connecter, et tout marche très bien (liste, conversations). Et parfois, si je fais "me connecter" avec l'application.. là, ou bien je suis directement déconnecté (parce que reçois une exception avec le readObject()), ou bien je ne suis pas déconnecté, mais je ne reçois plus aucun message (mais peux en envoyer aux autres), jusqu'à être déconnecté.

J'ai regardé un autre projet (1A/2A) qui utilise ces flux (jeu en ligne), et qui ne rencontre pas de problème. Pourtant, je ne vois pas de différence avec moi :( 

Auriez-vous une idée ? Je désespère.....

Merci ..!
Lassé par la pub ? Créez un compte
Tom's guide dans le monde