druduss2 | Bonjour,
J'aurai aimé avoir un bout de code à pointer et dire "ici ça ne marche pas et je sais pas pourquoi", comme indiqué dans le topic des bonnes pratiques, mais malheureusement ce n'est pas le cas.
Je suis confronté à un comportement bizarre de mon projet de client-server java par socket, que je n'arrive pas à comprendre ou à en isoler les causes.
Je vous explique :
Voulant développer un petit programme perso, et ayant déjà été confronté à la difficulté de faire communiquer plusieurs personnes utilisant le même programme, je me suis dit : Tiens, je vais développer une petite librairie client-server en java, utilisant les sockets. Je tiens à dire que j'avais réussi à créer une application client-server en java par socket il y a peu, mais que le code du serveur et du client était trop lié à l'application pour être réutilisé en l'état. J'ai donc créé un nouveau projet, que j'ai nommé LibraryNetworkMango, dont le but était de proposer un petit serveur java pouvant envoyer des Object java par sérialization.
Donc j'ai développé ce projet, qui marche bien, sauf un comportement que je ne comprend pas du tout.
Donc le problème :
- Lorsqu'un client (MangoClient) se connecte au serveur (MangoServer), le serveur l'accepte et lui donne un ID unique (PersonnalID), du côté client, lorsque je reçois cette ID unique, je considère que c'est interne, et je n’envoie pas de notification à l'application.
- Là, c'est l'application qui gère, dans mon cas j'envoie un objet donnant l'état de l'application client au serveur après avoir lancé le client.
- Le serveur reçoit un event (MangoServerEvent), qui contient un type (EventTypeServer) état OBJECTRECEIVED.
- A ce moment-là, le serveur (de l'application) décide de faire une MAJ avec les informations reçues du client, puis de tout ré-envoyer à tous les clients (note: le serveur est aussi une instance de mon application, et donc je rafraîchis le GUI avec les nouvelles informations du client, et ça s'affiche donc c'est bon).
- Le client reçoit la MAJ et rafraîchit son GUI, ça marche.
- A partir de là, je me retrouve confronté à un cas de figure bien particulier :
_ Toute modification du client est envoyé au serveur et affiché (la connexion dans ce sens marche).
_ Toute modification du serveur ne s'affiche pas côté client. J'ai mis des System.out.println(); côté client et serveur afin de lire ce que j'envoie et reçoit, et il s'avère que l'objet envoyé correspond, mais que l'objet reçu est toujours la première version de l'objet reçu (le premier objet envoyé par le serveur).
Voici une image représentant l'arborescence de mon projet sur Netbeans :
Il faut que je m'excuse pour la quantité de code qui va suivre, ne sachant pas où se trouve l'erreur...
Note : j'ai enlevé tous les commentaires afin de diminuer la quantité de code J'ai aussi enlevé la partie envoyer des String (je voulais que Mango offre la possibilité de choisir le mode de communication). J'ai aussi enlevé la partie affichant l'état au fur et à mesure.
Merci d'avance si vous prenez le temps de vous pencher sur mon problème, je suis bloqué dessus depuis trois jours...
MangoClient
Code complet (commentaire, affiche de l'état, possibilité d'envoyer des String) : 694 lignes.
Version allégé : 245 lignes.
Code :
- package newpackage;
- import CommonClass.*;
- import java.io.*;
- import java.net.InetAddress;
- import java.net.Socket;
- import java.net.SocketException;
- import java.net.UnknownHostException;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- public class MangoClient implements Runnable {
- private String password;
- private CommunicationType communicationType;
- private ObjectInputStream readerObjet;
- private ObjectOutputStream writerObjet;
- private BufferedReader readerString;
- private BufferedWriter writerString;
- public MangoClientListener mangoListener;
- private Socket serverClient;
- private Thread network;
- private String ip;
- private int port;
- private static boolean afficherLogTest = true;
- private int personalID;
- public MangoClient(String ip, int port, String password, CommunicationType communicationType, MangoClientListener mangoListener) {
- this.personalID = -1;
- this.ip = ip;
- this.port = port;
- this.communicationType = communicationType;
- this.password = password;
- this.mangoListener = mangoListener;
- }
- public MangoClient(String ip, int port, CommunicationType communicationType, MangoClientListener mangoListener) {
- this(ip, port, "", communicationType, mangoListener);
- }
- @Override
- public void run() {
- if (this.communicationType == CommunicationType.OBJECT) {
- while (this.network != null && this.readerObjet != null) {
- Capsule capsule;
- try {
- if ((capsule = (Capsule) this.readerObjet.readObject()) != null) {
- if (capsule.getMangoMessage() == MangoMessage.INTERN || capsule.getMangoMessage() == MangoMessage.INTERN_PERSONALID) {
- if (capsule.getMangoMessage() == MangoMessage.INTERN) {
- String temp = (String) capsule.getObjet();
- this.responseIntern(temp);
- } else { // INTERN_PERSONALID
- this.personalID = (int) capsule.getObjet();
- }
- } else {
- if (this.mangoListener != null) {
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(capsule.getObjet(), this.communicationType));
- }
- }
- }
- } catch (IOException ex) {
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.stop();
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- } catch (ClassNotFoundException ex) {
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
- }
- }
- private void sendINTERN(Object objet) {
- switch (this.communicationType) {
- case OBJECT:
- if (this.writerObjet != null) {
- Capsule capsule = new Capsule(objet, MangoMessage.INTERN);
- try {
- this.writerObjet.writeObject(capsule);
- this.writerObjet.flush();
- } catch (IOException ex) {
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.stop();
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- }
- break;
- }
- }
- public void send(Object objet) {
- switch (this.communicationType) {
- case OBJECT:
- if (this.writerObjet != null) {
- Capsule capsule = new Capsule(objet);
- try {
- this.writerObjet.writeObject(capsule);
- this.writerObjet.flush();
- } catch (IOException ex) {
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.stop();
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- }
- break;
- }
- }
- public void stop() {
- this.network = null;
- switch (this.communicationType) {
- case OBJECT:
- this.readerObjet = null;
- this.writerObjet = null;
- break;
- }
- try {
- this.serverClient.close();
- } catch (IOException ex) {
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- }
- public void launchMangoClient() {
- boolean err = false;
- try {
- this.serverClient = new Socket(this.ip, this.port);
- this.serverClient.setSoTimeout(2000); // we wait max 2 seconds before timeout error
- if (!this.serverClient.isConnected()) {
- err = true;
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- } catch (UnknownHostException ex) {
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- } catch (IOException ex) {
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- if (err == false) {
- InputStream inputStream = null;
- OutputStream outputStream = null;
- try {
- inputStream = this.serverClient.getInputStream();
- } catch (IOException ex) {
- err = true;
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- if (err == false) {
- switch (this.communicationType) {
- case OBJECT:
- try {
- this.readerObjet = new ObjectInputStream(new BufferedInputStream(inputStream));
- } catch (IOException ex) {
- err = true;
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- break;
- }
- try {
- outputStream = this.serverClient.getOutputStream();
- } catch (IOException ex) {
- err = true;
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- switch (this.communicationType) {
- case OBJECT:
- try {
- this.writerObjet = new ObjectOutputStream(outputStream);
- } catch (IOException ex) {
- err = true;
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- break;
- }
- InetAddress url = this.serverClient.getInetAddress();
- this.personalID = this.waitingForPersonalID();
- if (this.personalID == -1) {
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- this.network = new Thread(this);
- this.network.setName("RestoClient: Logged on: " + url.getHostAddress());
- this.network.setPriority(Thread.NORM_PRIORITY);
- this.network.start();
- try {
- this.serverClient.setSoTimeout(0);
- } catch (SocketException ex) {
- err = true;
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- } else {
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- }
- }
- }
- private void responseIntern(String temp) {
- String stringResponse = null;
- switch (temp) {
- case "INTERN/askpassword":
- stringResponse = this.password;
- break;
- default: // on reçoit la personalID sous la forme "INTERN/xxx"
- String id_string = temp.substring(7);
- this.personalID = Integer.parseInt(id_string);
- break;
- }
- if (stringResponse != null) {
- if (this.communicationType == CommunicationType.OBJECT) {
- this.sendINTERN(stringResponse);
- }
- }
- }
- public int getPersonalID() {
- return this.personalID;
- }
- private int waitingForPersonalID() {
- int personalID_local = -1;
- switch (this.communicationType) {
- case OBJECT:
- Capsule capsule;
- try {
- if ((capsule = (Capsule) this.readerObjet.readObject()) != null) {
- personalID_local = (int) capsule.getObjet();
- }
- } catch (IOException ex) {
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- this.stop();
- this.mangoListener.receiveMangoClientEvent(new MangoClientEvent(EventTypeClient.CLIENTCRASH));
- } catch (ClassNotFoundException ex) {
- Logger.getLogger(MangoClient.class.getName()).log(Level.SEVERE, null, ex);
- }
- break;
- }
- return personalID_local;
- }
- }
|
MangoServer
Code complet (commentaire, affiche de l'état, possibilité d'envoyer des String) : 407 lignes.
Version allégé : 215 lignes.
Code :
- package newpackage;
- import CommonClass.*;
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.ArrayList;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- public class MangoServer implements Runnable, MangoServerListener {
- private boolean acceptingClient;
- private int serverPort;
- private int maxClient;
- private String password;
- private CommunicationType communicationType;
- private boolean isPassword;
- private ArrayList<MangoSocket> clients;
- private ServerSocket server;
- private Thread seeker;
- private MangoServerListener mangoListener;
- private boolean isWaitingInternalCommand;
- private static boolean afficherLogTest = false;
- private boolean error;
- public MangoServer(int serverPort, int maxClient, String password, CommunicationType serverType, MangoServerListener mangoListener) {
- this.error = false;
- this.mangoListener = mangoListener;
- this.acceptingClient = true;
- this.serverPort = serverPort;
- this.maxClient = maxClient;
- this.password = password;
- this.communicationType = serverType;
- this.isWaitingInternalCommand = false;
- if (this.password == null) {
- this.isPassword = false;
- } else {
- if (this.password.equals("" )) {
- this.isPassword = false;
- } else {
- this.isPassword = true;
- }
- }
- this.clients = new ArrayList<>();
- try {
- this.server = new ServerSocket(this.serverPort);
- } catch (IOException ex) {
- this.closeMangoServer();
- this.mangoListener.receiveMangoServerEvent(new MangoServerEvent(EventTypeServer.SERVERCRASH));
- Logger.getLogger(MangoServer.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
- public MangoServer(int serverPort, int maxClient, CommunicationType serverType, MangoServerListener mangoListener) {
- this(serverPort, maxClient, "", serverType, mangoListener);
- }
- public void stopAcceptingClient() {
- this.acceptingClient = false;
- this.seeker = null;
- }
- public void startMangoServer() {
- this.seeker = new Thread(this);
- this.seeker.setName(" MangoServer: Client Seeker" );
- this.seeker.setPriority(Thread.MIN_PRIORITY);
- this.seeker.start();
- }
- public void closeMangoServer() {
- this.seeker.interrupt();
- this.seeker = null;
- try {
- this.server.close();
- } catch (IOException ex) {
- Logger.getLogger(MangoServer.class.getName()).log(Level.SEVERE, null, ex);
- }
- this.killAndRemoveAllClient();
- }
- @Override
- public void run() {
- boolean accept_new_client = true;
- while (this.acceptingClient == true && this.seeker != null && accept_new_client == true && this.error == false) {
- Socket client = null;
- if (this.server != null) {
- try {
- client = this.server.accept();
- } catch (IOException ex) {
- this.error = true;
- Logger.getLogger(MangoServer.class.getName()).log(Level.SEVERE, null, ex);
- }
- if (this.error == false) {
- if (this.isPassword) {
- this.askPasswordFromNewClient(new MangoSocket(client, this.communicationType, this));
- } else {
- this.acceptNewClient(new MangoSocket(client, this.communicationType, this));
- }
- }
- }
- if (this.maxClient > 0) {
- if (this.maxClient > this.countClient()) {
- accept_new_client = true;
- } else {
- accept_new_client = false;
- }
- }
- }
- }
- private void acceptNewClient(MangoSocket mangoSocket) {
- this.clients.add(mangoSocket);
- this.mangoListener.receiveMangoServerEvent(new MangoServerEvent(EventTypeServer.NEWCLIENT));
- }
- private void askPasswordFromNewClient(MangoSocket mangoSocket) {
- this.isWaitingInternalCommand = true;
- switch (this.communicationType) {
- case OBJECT:
- Capsule capsule = new Capsule("INTERN/askpassword", MangoMessage.INTERN);
- mangoSocket.send(capsule);
- break;
- }
- }
- private void sendNotificationWrongPasswordToNewClient(MangoSocket mangoSocket) {
- switch (this.communicationType) {
- case OBJECT:
- Capsule capsule = new Capsule("/wrongpassword", MangoMessage.INTERN);
- mangoSocket.send(capsule);
- break;
- }
- }
- public boolean respondToClient(Object objet, int personnalID) {
- boolean retour = false;
- MangoSocket mangoSocket = this.getMangoSocket(personnalID);
- if (mangoSocket != null) {
- retour = mangoSocket.send(objet);
- }
- return retour;
- }
- public boolean respondToAllClients(Object objet) {
- boolean zeroErreur = true;
- for (MangoSocket mangoSocket : this.clients) {
- if (mangoSocket != null) {
- boolean retour = mangoSocket.send(objet);
- if (retour == false) {
- zeroErreur = false;
- }
- }
- }
- return zeroErreur;
- }
- private MangoSocket getMangoSocket(int personnalID) {
- MangoSocket mangoSocket = null;
- for (MangoSocket r : this.clients) {
- if (r.getPersonalID() == personnalID) {
- mangoSocket = r;
- }
- }
- return mangoSocket;
- }
- private void killAndRemoveAllClient() {
- for (MangoSocket r : this.clients) {
- r.addMangoListener(null);
- r.kill();
- }
- }
- public int countClient() {
- return this.clients.size();
- }
- @Override
- public void receiveMangoServerEvent(MangoServerEvent mangoEvent) {
- if (this.isWaitingInternalCommand) {
- MangoSocket mangoClient;
- mangoClient = this.getMangoSocket(mangoEvent.getPersonnalID());
- String temp = "";
- if (mangoClient != null) {
- if (temp.equals(this.password)) {
- this.acceptNewClient(mangoClient);
- } else {
- this.sendNotificationWrongPasswordToNewClient(mangoClient);
- }
- }
- } else {
- switch (mangoEvent.getEventType()) {
- case LOSTCLIENT:
- this.removeAndKillClientByPersonnalID(mangoEvent.getPersonnalID());
- break;
- case OBJECTRECEIVED:
- mangoEvent = new MangoServerEvent(mangoEvent.getObjet(), this.communicationType);
- break;
- case STRINGRECEIVED:
- mangoEvent = new MangoServerEvent(mangoEvent.getString(), this.communicationType);
- break;
- }
- this.mangoListener.receiveMangoServerEvent(mangoEvent);
- }
- }
- private void removeAndKillClientByPersonnalID(int personnalID) {
- MangoSocket mangoSocketToDelete = this.getMangoSocket(personnalID);
- if (mangoSocketToDelete != null) {
- this.clients.remove(mangoSocketToDelete);
- mangoSocketToDelete.kill();
- }
- }
- }
|
MangoSocket
Code complet (commentaire, affiche de l'état, possibilité d'envoyer des String) : 397 lignes.
Version allégé : 153 lignes.
Code :
- package newpackage;
- import CommonClass.*;
- import java.io.*;
- import java.net.Socket;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- public class MangoSocket implements Runnable {
- private static int countOfID = 1;
- private int personalID;
- private CommunicationType communicationType;
- private Socket socketClient;
- private Thread thread;
- private ObjectInputStream readerObject;
- private ObjectOutputStream writerObject;
- private BufferedReader readerString;
- private BufferedWriter writerString;
- public MangoServerListener mangoListener;
- private static boolean afficherLogTest = true;
- public MangoSocket(Socket socketClient, CommunicationType serverType, MangoServerListener mangoListener) {
- this.mangoListener = mangoListener;
- this.personalID = MangoSocket.getID();
- System.out.println("personalID: " + this.personalID);
- this.communicationType = serverType;
- this.socketClient = socketClient;
- OutputStream outputStream = null;
- InputStream inputStream = null;
- try {
- outputStream = this.socketClient.getOutputStream();
- } catch (IOException ex) {
- Logger.getLogger(MangoSocket.class.getName()).log(Level.SEVERE, null, ex);
- }
- switch (this.communicationType) {
- case OBJECT:
- try {
- this.writerObject = new ObjectOutputStream(outputStream);
- } catch (IOException ex) {
- Logger.getLogger(MangoSocket.class.getName()).log(Level.SEVERE, null, ex);
- }
- break;
- }
- try {
- inputStream = this.socketClient.getInputStream();
- } catch (IOException ex) {
- Logger.getLogger(MangoSocket.class.getName()).log(Level.SEVERE, null, ex);
- }
- switch (this.communicationType) {
- case OBJECT:
- try {
- this.readerObject = new ObjectInputStream(new BufferedInputStream(inputStream));
- } catch (IOException ex) {
- Logger.getLogger(MangoSocket.class.getName()).log(Level.SEVERE, null, ex);
- }
- break;
- }
- if (this.communicationType == CommunicationType.OBJECT) {
- this.sendCapsule(new Capsule(this.personalID, MangoMessage.INTERN_PERSONALID));
- }
- this.thread = new Thread(this);
- this.thread.setName("MangoSocket " + this.personalID);
- this.thread.setPriority(Thread.MIN_PRIORITY);
- this.thread.start();
- }
- private static int getID() {
- return MangoSocket.countOfID++;
- }
- public int getPersonalID() {
- return personalID;
- }
- public void kill() {
- try {
- this.socketClient.close();
- } catch (IOException ex) {
- Logger.getLogger(MangoSocket.class.getName()).log(Level.SEVERE, null, ex);
- }
- this.thread = null;
- this.readerObject = null;
- this.writerObject = null;
- this.readerString = null;
- this.writerString = null;
- if (this.mangoListener != null) {
- this.mangoListener.receiveMangoServerEvent(new MangoServerEvent(EventTypeServer.LOSTCLIENT, this.personalID));
- }
- }
- public boolean send(Object objet) {
- boolean result = false;
- switch (this.communicationType) {
- case OBJECT:
- result = this.sendObject(objet);
- break;
- }
- return result;
- }
- private boolean sendObject(Object objet) {
- Capsule capsule = new Capsule(objet);
- return this.sendCapsule(capsule);
- }
- private boolean sendCapsule(Capsule capsule) {
- boolean result;
- if (this.communicationType == CommunicationType.OBJECT) {
- if (this.writerObject != null) {
- result = true;
- try {
- this.writerObject.writeObject(capsule);
- this.writerObject.flush();
- } catch (IOException ex) {
- Logger.getLogger(MangoSocket.class.getName()).log(Level.SEVERE, null, ex);
- }
- } else {
- result = false;
- }
- } else {
- result = false;
- }
- return result;
- }
- @Override
- public void run() {
- switch (this.communicationType) {
- case OBJECT:
- while (this.readerObject != null) {
- Capsule capsule;
- try {
- if ((capsule = (Capsule) this.readerObject.readObject()) != null) {
- if (this.personalID != -1) {
- this.mangoListener.receiveMangoServerEvent(new MangoServerEvent(capsule.getObjet(), this.communicationType));
- }
- }
- } catch (IOException ex) {
- this.kill();
- Logger.getLogger(MangoSocket.class.getName()).log(Level.SEVERE, null, ex);
- } catch (ClassNotFoundException ex) {
- Logger.getLogger(MangoSocket.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
- break;
- }
- }
- public void addMangoListener(MangoServerListener mangoListener) {
- this.mangoListener = mangoListener;
- }
- }
|
|