IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Plateformes (Java EE, Jakarta EE, Spring) et Serveurs Discussion :

Incohérence _numClients - Développement d'un serveur multithread simple


Sujet :

Plateformes (Java EE, Jakarta EE, Spring) et Serveurs

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2017
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2017
    Messages : 53
    Points : 26
    Points
    26
    Par défaut Incohérence _numClients - Développement d'un serveur multithread simple
    Bonjour minosis,
    J'ai lu un article de Developpez.net sur la création d'un serveur multithread simple et j'ai décidé de m'inspirer de leur code pour créer mon propre serveur multithread. J'y ai ajouté un système de LogIn via un fichier qui contient tous les utilisateurs enregistrés, j'ai ajouté en plus du du Vector _tabclients deux autres vecteurs enregistrant le username du client et son adresse IP.
    Cependant j'ai un problème par rapport au nombre retourné par la fonction addClient(). En effet il me retourne 49 au lieu de 0 lorsqu'un utilisateur est connecté. J'ai regardé plusieurs heures mon code sans savoir d'où provient l'erreur. Ce serait un grand plaisir si vous pouviez m'aider à trouver d'où vient cette incohérence qui fausse mon programme.

    Avec ceci je vous joins le code mon programme serveur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    package com.stol3nd_hack_.server;
     
    import java.io.PrintWriter;
    import java.net.InetAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.Vector;
     
    public class Server {
     
    	private static int _nbClients = 0;
    	private static Vector _tabClients = new Vector();
    	private static Vector ip_clientArray = new Vector();
    	private static Vector usernameArray = new Vector();
     
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
     
    		Server server = new Server();
     
    		try{
     
    			Integer port;
    			if(args.length<=0) port = new Integer("25565");
    			else port = new Integer(args[0]);
     
    			 ServerSocket ss = new ServerSocket(port.intValue());
    			 printWelcome(port);
     
    			 while(true){
     
    				 Socket s_client = ss.accept();
    				 new AuthenticateThread(s_client, server);
    			 }
     
    		}catch(Exception e){}
     
    	}
     
    	synchronized public void sendAll(String message)
    	  {
    	    PrintWriter out; // declaration d'une variable permettant l'envoi de texte vers le client
    	    for (int i = 0; i < _tabClients.size(); i++) // parcours de la table des connectés
    	    {
    	      out = (PrintWriter) _tabClients.elementAt(i); // extraction de l'élément courant (type PrintWriter)
    	      if (out != null) // sécurité, l'élément ne doit pas être vide
    	      {
    	      	// ecriture du texte passé en paramètre (et concaténation d'une string de fin de chaine si besoin)
    	        out.println(message);
    	        out.flush(); // envoi dans le flux de sortie
    	      }
    	    }
    	  }
     
    	static private void printWelcome(Integer port){
    		System.out.println("------------------------------------");
    		System.out.println("STOL3ND Hacking Server : By STO Regin - Chatting Server");
    		System.out.println("------------------------------------");
    		System.out.println("Last Version : v0.01");
    		System.out.println("------------------------------------");
    		System.out.println("Beginning port : "+ port.toString());
    		System.out.println("------------------------------------");
    	}
     
    	synchronized public static  int addClient(PrintWriter out, String username, String ipadress)
    	  {
    	    _nbClients++; 
    	    _tabClients.addElement(out);
    	    usernameArray.addElement(username);
    	    ip_clientArray.addElement(ipadress);
    	    return _tabClients.size()-1;
    	  }
     
    	synchronized public int getNbClients(){
    	    return _nbClients; // retourne le nombre de clients connectés
    	}
    	synchronized public void delClient(int i) {
    	    _nbClients--; // un client en moins ! snif
    	    if (_tabClients.elementAt(i) != null) // l'élément existe ...
    	    {
    	      _tabClients.removeElementAt(i); // ... on le supprime
    	    }
     
    	    if (ip_clientArray.elementAt(i) != null) // l'élément existe ...
    	    {
    	      ip_clientArray.removeElementAt(i); // ... on le supprime
    	    }
     
    	    if (usernameArray.elementAt(i) != null) // l'élément existe ...
    	    {
    	      usernameArray.removeElementAt(i); // ... on le supprime
    	    }
    	}
     
    	synchronized public boolean already_connected(String username){
    		if(usernameArray.contains(username)){
    			return true;
    		}else{
    			return false;
    		}
    	}
     
    }

    AuthenticateThread.java :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    package com.stol3nd_hack_.server;
     
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.InetAddress;
    import java.net.Socket;
     
    public class AuthenticateThread implements Runnable{
     
     
    	private Thread _t;
    	private Socket s;
    	private Server server;
    	private PrintWriter out;
    	private BufferedReader in;
    	private boolean authenticate = false;
    	private String username;
    	private int num_client;
    	private String ip_client;
     
     
    	AuthenticateThread(Socket s_client, Server server) {
    		s = s_client;
    		this.server = server;
    		 try
    		    {
    		      out = new PrintWriter(s.getOutputStream());
    		      in = new BufferedReader(new InputStreamReader(s.getInputStream()));
    		    }
    		    catch (IOException e){ }
     
    		    _t = new Thread(this); // instanciation du thread
    		    _t.start();
    	}
     
     
     
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		try {
     
    			while(!authenticate){
     
    				out.println("Enter your username : ");
    				out.flush();
     
    				username = in.readLine();
     
    				out.println("Enter your password : ");
    				out.flush();
     
    				String password = in.readLine();
     
    				String login = new String(username+"@"+password);
     
    				File ad_login = new File("ad_stol3nd.dat");
    				BufferedReader br = new BufferedReader(new FileReader(ad_login));
    				String line;
    				while ((line = br.readLine()) != null) {
    				   if(line.equals(login)){
    					   if(!server.already_connected(username)){
    						   authenticate = true;
    					   }						 				   
    				   }
    				}
    				br.close();
    				if(!authenticate){
    					out.println("Identifiants incorrects! Réessayez! (Si vous êtes sûr de vos identifiants, vous êtes peut-être déjà connecté sur un autre appareil");
    					out.flush();
    				}
     
    			}
    			out.println("Connexion réussi!");
    			out.flush();
     
    			new ServerThread(s,server,username,s.getInetAddress().getHostAddress(),out,in);
     
     
    		} catch (IOException e) {try {s.close();} catch (IOException e1) {} e.printStackTrace();}
     
    	}
     
    }
    ServerThread.java :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    package com.stol3nd_hack_.server;
     
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.util.Scanner;
     
    public class ServerThread implements Runnable{
     
    	private Thread _t;
    	private Server server;
    	private Socket s;
    	private PrintWriter out;
    	private BufferedReader in;
    	private int num_client;
    	private String username;
    	private Scanner sc = new Scanner(System.in);
    	private String ipaddress;
     
     
    	ServerThread(Socket s, Server server, String username, String ipaddress, PrintWriter out, BufferedReader in){
    		this.server = server;
    		this.s = s;
    		this.username = username;
    		this.ipaddress = ipaddress;
    		this.out = out;
    		this.in = in;
     
    		try {
     
    			num_client = server.addClient(out, username, ipaddress);		
    			out.println(num_client);
    			out.flush();
     
    			String new_client =in.readLine();
    			String msg = new_client.replace("sendall", "");
    			server.sendAll(msg);
     
    			_t = new Thread(this);
    			_t.start();
     
     
    		} catch (Exception e) {}
     
    	}
     
     
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		String msg_recu ="";
    		while(!msg_recu.equals("stop")){
     
    			try {
     
    				msg_recu = in.readLine();
    				System.out.println(msg_recu);
     
     
    			} catch (Exception e) {
    				server.delClient(num_client);
    				System.out.println(server.getNbClients());
    				System.exit(0);
    				try {
    					in.close();
    					out.close();
    					s.close();
    				} catch (IOException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				}
    			}
     
    		}
     
    	}
     
    }
    Si vous avez besoin du code client, n'hésite pas à me le demander. Merci d'avance.

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Si tu regardes ce que retourne addClient, c'est l'index du client ajouté dans le vecteur. Déjà, tu pourrais regarder ce que tu as dans ce vecteur, pour te faire une idée de ce qui ne va pas (en debug, ou par simple trace).

    Indice : à chaque fois qu'un client se connecte, un nouveau ServerThread est créé, ce qui ajoute ce client dans le vecteur. Si un client envoie STOP, son thread s'arrête, mais son "client" reste dans le vecteur. Si 1 million de connexions se terminent bien par un message STOP, tu as 1 million de clients qui trainent dans le vecteur...

    Par ailleurs, dès qu'une liaison avec un client se coupe, tu fais un System.exit(0) ! Mettons que ton serveur soit en ligne, 100 personnes se connectent dessus, l'une d'entre elles éteint son pc, boum, ton serveur s'arrête !

    De plus, en supposant qu'on vire ce System.exit(0), lorsqu'il y a une erreur lors de la lecture du message dans la socket, tu supprimes le client correspondant à ce retour de addClient dans le vecteur. Que se passe-t-il mettons si :
    1. un client A est ajouté dans le vecteur, le retour est 0
    2. un client B est ajouté dans le vecteur, le retour est 1
    3. la liaison avec le client A se coupe (peu importe pourquoi), ce qui provoque une exception, on supprime donc l'élément 0 du vecteur (il en reste donc 1 dedans
    4. la liaison avec le client B se coupe, ce qui provoque une exception, on supprime donc l'élément 1 du vecteur, qui n'en contient que 1 : boum !
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2017
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2017
    Messages : 53
    Points : 26
    Points
    26
    Par défaut
    Citation Envoyé par joel.drigo Voir le message
    Salut,

    Si tu regardes ce que retourne addClient, c'est l'index du client ajouté dans le vecteur. Déjà, tu pourrais regarder ce que tu as dans ce vecteur, pour te faire une idée de ce qui ne va pas (en debug, ou par simple trace).

    Indice : à chaque fois qu'un client se connecte, un nouveau ServerThread est créé, ce qui ajoute ce client dans le vecteur. Si un client envoie STOP, son thread s'arrête, mais son "client" reste dans le vecteur. Si 1 million de connexions se terminent bien par un message STOP, tu as 1 million de clients qui trainent dans le vecteur...

    Par ailleurs, dès qu'une liaison avec un client se coupe, tu fais un System.exit(0) ! Mettons que ton serveur soit en ligne, 100 personnes se connectent dessus, l'une d'entre elles éteint son pc, boum, ton serveur s'arrête !

    De plus, en supposant qu'on vire ce System.exit(0), lorsqu'il y a une erreur lors de la lecture du message dans la socket, tu supprimes le client correspondant à ce retour de addClient dans le vecteur. Que se passe-t-il mettons si :
    1. un client A est ajouté dans le vecteur, le retour est 0
    2. un client B est ajouté dans le vecteur, le retour est 1
    3. la liaison avec le client A se coupe (peu importe pourquoi), ce qui provoque une exception, on supprime donc l'élément 0 du vecteur (il en reste donc 1 dedans
    4. la liaison avec le client B se coupe, ce qui provoque une exception, on supprime donc l'élément 1 du vecteur, qui n'en contient que 1 : boum !

    J'ai vérifié ce que rétourné la fonction addClient grâce un System.out.print() et j'obtiens 0. J'ai donc cherché d'où venait le problème et j'ai découvert que c'est durant le transfert du int num_client que la valeur s'en retrouvait modifié.
    J'ai lu ce que tu m'as dis à propos du System.exit(0) qui s'activait si il y avait une erreur lors de la lecture du msg, je l'ai donc supprimé.
    Je l'ai remplacé par ce code-ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    String msg_recu ="";
    		while(!msg_recu.equals("stop")){
     
    			try {
     
    				msg_recu = in.readLine();
    				System.out.println(msg_recu);
     
     
    			} catch (Exception e) {}			
    		}
    		server.delClient(num_client);
    		System.out.println(server.getNbClients());
    		try {
    			in.close();
    			out.close();
    			s.close();
    		} catch (IOException e1) {
    			// TODO Auto-generated catch block
    			e1.printStackTrace();
    		}
    De plus, je me suis posé la question sur le dernier problème que tu m'as posé. Il faudrait faire en sorte que le num_client de chaque thread soit constamment actualisée à chaque fois qu'un client se déconnecte. Je suppose que ceci doit être fait dans une autre thread.

    Comment faire ça se fait que la valeur reçu du num_client soit changé durant l'échange?

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par wildshadow956 Voir le message
    J'ai vérifié ce que rétourné la fonction addClient grâce un System.out.print() et j'obtiens 0. J'ai donc cherché d'où venait le problème et j'ai découvert que c'est durant le transfert du int num_client que la valeur s'en retrouvait modifié.
    [...]
    Comment faire ça se fait que la valeur reçu du num_client soit changé durant l'échange?
    Ah, tu parlais de la valeur côté client ! M'étonnerait que cette valeur soit modifiée lors du transfert. Je pencherais plus pour une lecture mal faite. Faudrait voir aussi exactement comment tu sais que ça vaut 0 (où tu fais ta trace). D'autant que l'ASCII 49, c'est le chiffre 1, pas si loin donc du 0. Tu peux montrer la partie du client qui fait cette lecture ?

    Citation Envoyé par wildshadow956 Voir le message
    De plus, je me suis posé la question sur le dernier problème que tu m'as posé. Il faudrait faire en sorte que le num_client de chaque thread soit constamment actualisée à chaque fois qu'un client se déconnecte. Je suppose que ceci doit être fait dans une autre thread.
    Le problème est qu'il ne faut pas travailler avec la position dans un vecteur, mais avec un numéro unique qui ne dépend pas de la position dans une collection, ou de n'importe quoi d'autre (et surtout pas d'un ordre d'exécution).
    Tu peux générer un numéro unique par exemple avec un AtomicInteger static :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public class Server {
     private static final AtomicInteger ID_FACTORY = new AtomicInteger();
     
     private static int getNewId() {
           return ID_FACTORY.getAndIncrement();
     }
     
     /**...*/
    Au lieu de stocker tes clients dans une liste, tu les stockes dans une map (qui associe une clef avec un valeur), avec l'id en clef..

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
     
    public class Server {
      private static final AtomicInteger ID_FACTORY = new AtomicInteger();
     
     private static int getNewId() {
           return ID_FACTORY.getAndIncrement();
     } 
    	private static final Map<Integer, PrintWriter> clients  = new ConcurrentHashMap<>(); // avec cette map tu n'es plus obligé de synchroniser les méthodes
     
     
    	public static  int addClient(PrintWriter out, String username, String ipadress) {
    	    int id = getNewId();
    	    clients  .put(id, out);
                /*...*/
    	    return id;
    	  }
     
    	public int getNbClients(){
    	    return clients.size(); // retourne le nombre de clients connectés
    	}
    	public void delClient(int id) {
    	     clients.remove(id);
    	}
     
     
    }
    Au lieu d'utiliser 3 vecteurs ou 3 maps, pour stocker 3 informations concernant le même "id", fait une classe Client :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Client {
          public final PrintWriter out;
          public final String username;
          public final String ip;
          public Client(PrintWriter out, String username, String ip) {
               this.out=out;
               this.username=username;
               this.ip=ip;
          }
    }
    du coup :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    private static final Map<Integer, Client> clients  = new ConcurrentHashMap<>();
     
    public static  int addClient(PrintWriter out, String username, String ipadress) {
    	    int id = getNewId();
    	    clients  .put(id, new Client(out, username, idadress));
                /*...*/
    	    return id;
    	  }
     
    public static Client getClient(int id) {
              return clients.get(id);
    }
    Reste à faire : already_connected(String username){. Avec une Map<Integer, Client> on ne peut plus utiliser directement un contains. On peut le faire par parcours, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public static boolean isAlreadyConnected(String username) {
           return clients.values().stream().map(c-> c.username).filter(name-> name.equals(username)).count()>0;
    }
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public static boolean isAlreadyConnected(String username) {
           return clients.values().stream().collect(Collectors.grouping(c-> c.username)).contains(username);
    }
    Ou utiliser une seconde map avec un compteur associé au username comme clef (mais ça obligerait de synchroniser de nouveau).
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2017
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2017
    Messages : 53
    Points : 26
    Points
    26
    Par défaut
    Merci pour cette réponse, cela simplifie grandement mon code(je tacherai de me souvenir de cette technique). Voici le code client une fois le login réussi:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    package com.stol3nd_hack_.client;
     
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.util.Scanner;
     
    public class ConnectedClientThread implements Runnable{
     
    	private Socket s;
    	private PrintWriter out;
    	private BufferedReader in ;
    	private String username;
    	private int num_client;
    	private String ipaddress;
    	private Thread _t;
    	private Scanner sc = new Scanner(System.in);
     
    	ConnectedClientThread(Socket s, String username, String ip){
    		this.s = s;
    		this.username = username;
    		this.ipaddress= ip;
     
    		try {
     
    			out= new PrintWriter(s.getOutputStream());
    			in = new BufferedReader(new InputStreamReader(s.getInputStream()));
     
    			num_client = in.read();
    			System.out.println("Vous êtes le client n°"+num_client);
    			System.out.println("-------------------");
    			System.out.println("Send to all : sendall + msg");
    			System.out.println("-------------------");
    			System.out.println("Send private msg to someone : sendto \\username + msg");
    			System.out.println("-------------------");
    			System.out.println("Connected users list : client list");
    			System.out.println("-------------------\n\n");
     
    			_t = new Thread(this);
    			_t.start();
     
    		} catch (IOException e) {e.printStackTrace();}
     
     
     
    		_t = new Thread(this);
    		_t.start();
    	}
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		String msg ="";
     
    		while(!msg.equals("stop")){
     
    			System.out.print(username+"@"+ipaddress+" > ");
    			msg = sc.nextLine();
    			System.out.println(msg);
    			out.println(msg);
    			out.flush();
     
    		}
     
    		try{
    			out.close();
    			in.close();
    			sc.close();
    			s.close();
    			System.exit(0);
    		}catch(Exception e){}
     
     
    	}
     
    }
    En fait, sans faire exprès j'ai effacé le fichier originel du coup j'ai refait ce code à la va-vite et cela me lève une exception lors de l'entrée dans la boucle, au moment où j'entre ma première commande:


    Nom : exception.PNG
Affichages : 246
Taille : 16,5 Ko

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    1. Pour le problème de l'exception, c'est que visiblement tu as plusieurs clients, chacun ayant un thread, mais qui partage le System.in en entrée via un Scanner.

      Tu ne peux pas faire ça. Le Scanner est bufferisé : peu importe comment tu lis, le scanner en interne lit lui par ensemble d'octets, en quelque sorte d'avance. En multithread, tu ne contrôles rien : un thread peu lire d'avance des octets sous le nez d'un autre thread, qui lui va planter, parce qu'il est en cours de lecture et qu'on lui bouffe ce qu'il est en train de lire...
      Le moyen le plus simple est encore de lancer plus programme client dans plusieurs JVM. Sinon, il va falloir siouxer, faire une sorte d'agenceur avec une instance unique de Scanner, qui va être appelé successivement par chaque client, le scanner n'étant utilsé que par un client (=un thread) à la fois.
    2. Pour le problème du 49, c'est bien ce que je disais :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      num_client = in.read();
      read() retourne un int, qui est la valeur d'un octet dans le flux.
      Quand tu écris un int côté serveur via un PrintWriter, celui-ci est transformé en chaîne de caractères, selon un encodage particulier (celui par défaut de ta machine), qui est probablement basé sur ASCII : donc le 1 int est transformé en chaîne de caractères "1", qui lui est codé via le code ASCII 49. Donc quand tu lis le flux, tu lis 49. Il faut convertir le flux en String.
      On pourrait le transformer simplement en caractère avec un cast en char. Mais tu ne sais pas combien de caractères il y a : l'identifiant ça peut être 1, 12, 340, 2302349, etc... Bon, ce qui simplifie le problème, c'est que tu n'envoies que ça au client. Donc tu peux utiliser in.readLine() pour lire le message. Et ensuite tu le convertis en int : num_client = Integer.parseInt(in.readLine());Si tu comptes envoyer d'autres informations, il faudra prévoir un moyen pour le client de découper le message en information. Un séparateur, par exemple un \n, ce qui permet de dire que chaque ligne est une information différente et d'utiliser readLine() pour chacune d'entre elles. Sinon, on peut utiliser un autre caractère, la virgule par exemple, et utiliser la méthode split pour séparer les informations sur une même ligne : String[] info = in.readLine().split(","); et on récuperait le numéro client par num_client = Integer.parseInt(info[0]);
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2017
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2017
    Messages : 53
    Points : 26
    Points
    26
    Par défaut
    J'ai un problème, après avoir modifié le code de façon avoir num_client, je teste et le client ne réagit plus avant de recevoir celui-ci. Petite capture pour te montrer :

    Nom : erreur.PNG
Affichages : 249
Taille : 32,4 Ko

    J'ai fait plusieurs debug à l'aide sys.out pour savoir d'où ça venait.

  8. #8
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    tu fais un bien un out.println( num_client ) côté serveur ? Tu n'as pas changé ça ? Le flush() est toujours là aussi ?
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2017
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2017
    Messages : 53
    Points : 26
    Points
    26
    Par défaut
    Citation Envoyé par joel.drigo Voir le message
    tu fais un bien un out.println( num_client ) côté serveur ? Tu n'as pas changé ça ? Le flush() est toujours là aussi ?
    oui, tout est en place

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2017
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2017
    Messages : 53
    Points : 26
    Points
    26
    Par défaut
    Citation Envoyé par joel.drigo Voir le message
    tu fais un bien un out.println( num_client ) côté serveur ? Tu n'as pas changé ça ? Le flush() est toujours là aussi ?
    À propos de l'erreur causé par l'utlisation du Scanner, je l'ai remplacé par un BufferedReader pour détecter les entrées clavier.
    Par allieurs comment se fait-il que le système d'entrée de commande s'affiche deux fois (username@ip_address)?

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2017
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2017
    Messages : 53
    Points : 26
    Points
    26
    Par défaut
    En fait c'est bon j'ai trouvé la solution

  12. #12
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2017
    Messages
    53
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2017
    Messages : 53
    Points : 26
    Points
    26
    Par défaut
    Citation Envoyé par joel.drigo Voir le message
    tu fais un bien un out.println( num_client ) côté serveur ? Tu n'as pas changé ça ? Le flush() est toujours là aussi ?
    J'ai redémarrer Eclipse et comme par magie ça a marché. Merci pour tout joel.drigo.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Arrêt d'un serveur multithread
    Par bambou dans le forum Entrée/Sortie
    Réponses: 7
    Dernier message: 07/07/2010, 16h04
  2. Question Serveur Multithread
    Par Mr_Chut dans le forum Réseau
    Réponses: 10
    Dernier message: 09/06/2006, 17h27
  3. [Architecture] Conseil pour développement appli Client/Serveur
    Par etiennegaloup dans le forum Développement Web en Java
    Réponses: 11
    Dernier message: 22/01/2006, 11h44
  4. Réponses: 5
    Dernier message: 11/01/2006, 07h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo