Serveur multi clients

cs_romain117 Messages postés 53 Date d'inscription lundi 29 juin 2009 Statut Membre Dernière intervention 21 juillet 2013 - 24 nov. 2009 à 01:15
cs_romain117 Messages postés 53 Date d'inscription lundi 29 juin 2009 Statut Membre Dernière intervention 21 juillet 2013 - 24 nov. 2009 à 22:45
Bonjour.

Je veux réaliser un serveur où plusieurs clients peuvent se connecter. J'ai un fichier Serveur.java et Client.java. Je travaille sous Eclipse (en lançant plusieurs sessions).
Lorsqu'un client écrit un message, ça doit l'envoyer au serveur qui ensuite renvoie ce message à tous les autre clients.
Des le début ça bloque : [size=300]
/sizesi un client écrit un message, le premier est envoyé au serveur (mais uniquement au serveur) et si le client écrit un 2ème message là il y a une erreur : java.io.EOFException.
J'ai pu isoler la ligne où apparaît l'erreur : dans le fichier Serveur.java, dans la fonction run(), il s'agit de la ligne ois.close();

J'aimerais que vous m'expliquiez cette erreur car je ne comprends pas (et si le cœur vous en dit, m'expliquer pourquoi le reste ne marche pas ).

Voici les deux fichiers :

Serveur.java


/*

**** Chat multiclient - M1I 2008 *****

* Server.java

*

*/





// Packages à inclure

import java.net.*;

import java.io.*;

import java.util.Vector;



public class Server implements Runnable

{

// Déclaration des attributs de la classe



private int listenPort ;

private InetAddress inetAddress ;

private ServerSocket ss;

private Thread _t;

Socket _s ;

private String[] logins = new String[20];

Vector clients = new Vector();

int nbClients = 0;





// Déclaration des méthodes



/** Constructeur de la classe Serveur */

public Server()

{

}



/** Méthode permettant d'introduire le numéro de port du serveur */

private void setListenPort(int _listenPort)

{

this.listenPort = _listenPort ;

}



/** Méthode permettant de retourner le numéro de port du serveur */

public int getPort()

{

return listenPort ;

}



/** Méthode permettant de lancer le serveur

* @throws IOException */

private void launch() throws IOException

{



// 1. Créer la socket du serveur : ServerSocket(int _port)

//int _port = getPort() ;

ss = new ServerSocket (listenPort);



System.out.println("Serveur en execution...");



try

{

while(true)

{



// 2. Appeler la méthode 'accept()' du ServerSocket créée en 1.

_s = ss.accept ();



// 3. Ajouter la nouvelle connexion dans un vecteur (ou tableau) contenant toutes les connexions

nbClients++ ;

clients.addElement(_s) ; // ou clients.add(_s)



// 4. Appeler la méthode _t.start() permettant de lancer run() (run() : permet de traiter les connexions des clients)

_t = new Thread(this);

_t.start();

}

}



catch(Exception e)

{

System.out.println("Erreur socket ...."+e);

System.exit(0);

}

}



public void run()

{

try

{

// 1. Retirer la dernière socket du vecteur

Socket sck=(Socket)clients.lastElement();



// 2. Récupérer le flux d'entrée de la socket (méthode getInputStream() de la classe Socket)

InputStream is = sck.getInputStream ();

ObjectInputStream ois = new ObjectInputStream (is);

Object obj;



// 3. Lire le premier message envoyé par le client (méthode bloquante, par exemple : readObject()), il s'agit du login de l'utilisateur

obj = ois.readObject();

logins[nbClients-1]=(String) obj;



// 4. Imprimer le message

System.out.println(logins[nbClients-1]);





// 5. Lire le message envoyé par le client (méthode bloquante)

do
{
//InputStream is2 = sck.getInputStream ();

//ObjectInputStream ois2 = new ObjectInputStream (is2);
Object obj2 = ois.readObject();

String msg=(String) obj2;



// 6. Imprimer le message

System.out.println(msg);
ois.close();
//System.out.println("Salut ca va ??);



// 7. Envoyer le message lu à tous les autres clients, le précéder par le login de l'utilisateur concerné

// Utilisation de getOutputStream() et writeObject.

msg = logins[nbClients-1] + " : " + msg;
System.out.println(nbClients);

for (int i=0 ; i<nbClients ; i++)

{

Socket sck1=(Socket)clients.elementAt(i);

OutputStream os = sck1.getOutputStream ();

ObjectOutputStream oos = new ObjectOutputStream (os);

if (!sck1.equals(sck))

{

obj = (Object) msg;

oos.writeObject(obj);

msg = (String) obj;

oos.writeObject(msg);

}
sck1.close();

}



}
while(true);





}

catch(Exception e){}

}







//////////////////////////////////////////////////////////////////////////////////////////////

// Méthode principale : 'main'

//

// Le programme prendra 1 parametre : le numero de port à surveiller

//

//////////////////////////////////////////////////////////////////////////////////////////////





public static void main(String arg[]) throws IOException

{

Server server = new Server();

int port =9999 /*Integer.parseInt (arg[0])*/;

server.setListenPort(port);

server.launch();

}



}



Et Client.java


/*

**** Chat multiclient - M1I 2008 *****

* Client.java

*

*/



// Packages à inclure

import java.net.*;

import java.io.*;





public class Client implements Runnable
{



// Déclaration des attributs de la classe



private int port ;

private String host;

private InetAddress inetAddress ;

Thread t ;

Socket s ;

String login ;



// Déclaration des méthodes



/** Constructeur de la classe Client */



public Client (/*int port*/) //throws IOException

{

//port=getPort();

//s = new Socket (host,port);

}





/** Méthode déclenchée après appel de 't.start()', son rôle consiste à lire et afficher les messages envoyés par le serveur*/

//Il s'agit principalement des messages envoyés par les autres utilisateurs (clients) */



public void run()
{

try
{

while(true)
{

// 1. Récupérer le flux d'entrée de la socket s (méthode getInputStream() de la classe Socket)

InputStream is = s.getInputStream ();

ObjectInputStream ois = new ObjectInputStream (is);

//obj = (Object) msg ;

// 2. Lire le message envoyé par le serveur (méthode bloquante, par exemple : readObject())

Object obj = ois.readObject();

// 3. Convertir l'objet ('Object') reçu en une chaine de caractères ('String')

String msg = (String) obj;

// 4. Afficher la chaine de caractères

System.out.println(msg);

}

}
catch(Exception e)

{

System.out.println(e);

}

}




/** Méthode permettant de lire une chaine de caractères depuis la ligne de commandes */

public String readMessage()throws IOException
{

String s="";

char c;

while ((c=(char)System.in.read())!='\n')

s=s+c;

return s;

}



/** Méthode permettant de se connecter au serveur, de lire les chaines de caractères depuis une ligne de commandes et de les envoyer au serveur. La chaine 'Bye' doit mettre fin à la connexion*/

public void launch()
{

try
{

String msg;

// 1. Créer la socket

System.out.println("Connexion au serveur...");

s = new Socket(getInetAddress(),getPort());



// 2. Lancer le Thread (méthode 'start') permettant de recevoir les réponses du serveur

t = new Thread(this);

t.start();

OutputStream os ;

ObjectOutputStream oos ;

os = s.getOutputStream();

oos = new ObjectOutputStream(os);

oos.writeObject(login);



// 3. Récupérer le flux de sortie de la socket (méthode getOutputStream() de la classe Socket)

do
{
//OutputStream os = s.getOutputStream();

//ObjectOutputStream oos = new ObjectOutputStream(os);

//String msg = "Message du Client";

msg=Lire.S();
System.out.println("Réception des messages en cours... \n");

//Object obj=(Object) msg;

// 4. Ecrire le message sur le flux de sortie de la socket (méthode writeObject());
oos.writeObject(msg);
}
// 5. Mettre fin à la connexion si le message envoyé est 'Bye'
while(!msg.equals("Bye"));
s.close();
System.out.println("Vous êtes deconnecté du serveur");



}


catch(IOException e)
{

System.out.println("Erreur de sérialisation "+e);

}

}



/** Méthode permettant d'introduire le numéro de port surveillé par le serveur */

public void setPort(int p)
{

if(p >0)

{

port=p;

}

}



/** Méthode permettant de retourner le numéro de port du serveur */

public int getPort()
{

return port;

}




/** Méthode permettant de retourner l'adresse IP du serveur */

public InetAddress getInetAddress()
{

return this.inetAddress;//this->pour une variable globale qui aurait le même nom que le paramètre (ici on peut ne pas le mettre)

}




/** Méthode permettant d'introduire le nom ou l'IP du serveur

* @throws UnknownHostException */

public void setInetAddress (String machineName/*InetAddress inetAddress*/) throws UnknownHostException
{

// 'if(inetAddress!='NULL')

// {

try

{

inetAddress=InetAddress.getByName(machineName);

}

catch(Exception e)

{



}

//inetAddress=InetAddress.getLocalHost(); //récupérer l'adresse IP de la machine

// }

}




/** Méthode permettant d'introduire le login de l'utilisateur */



public void getLogin() throws IOException {

System.out.print("Entrer votre login SVP : ");

this.login=readMessage();

}



public void setLogin(String _login){

this.login=_login;

}






//////////////////////////////////////////////////////////////////////////////////////////////

// Méthode principale : 'main'

//

// Le programme prendra 2 paramètres : une adresse ou un nom de serveur, un numéro de port.

//

//////////////////////////////////////////////////////////////////////////////////////////////



public static void main(String[] arg) throws UnknownHostException, IOException
{

Client em = new Client();

em.setInetAddress("localhost");

em.setPort(9999);

em.getLogin();

em.launch();

}




}


Désolé pour la longueur.


Merci d'avance pour votre aide.

3 réponses

cs_romain117 Messages postés 53 Date d'inscription lundi 29 juin 2009 Statut Membre Dernière intervention 21 juillet 2013 1
24 nov. 2009 à 01:35
Bonjour.

Je veux réaliser un serveur où plusieurs clients peuvent se connecter. J'ai un fichier Serveur.java et Client.java. Je travaille sous Eclipse (en lançant plusieurs sessions).
Lorsqu'un client écrit un message, ça doit l'envoyer au serveur qui ensuite renvoie ce message à tous les autre clients.
Des le début ça bloque :
si un client écrit un message, le premier est envoyé au serveur (mais uniquement au serveur) et si le client écrit un 2ème message là il y a une erreur : java.io.EOFException.
J'ai pu isoler la ligne où apparaît l'erreur : dans le fichier Serveur.java, dans la fonction run(), il s'agit de la ligne ois.close();

J'aimerais que vous m'expliquiez cette erreur car je ne comprends pas (et si le cœur vous en dit, m'expliquer pourquoi le reste ne marche pas ).

Voici les deux fichiers :

Serveur.java

/*

**** Chat multiclient - M1I 2008 *****

* Server.java

*

*/





// Packages à inclure

import java.net.*;

import java.io.*;

import java.util.Vector;



public class Server implements Runnable

{

// Déclaration des attributs de la classe



private int listenPort ;

private InetAddress inetAddress ;

private ServerSocket ss;

private Thread _t;

Socket _s ;

private String[] logins = new String[20];

Vector clients = new Vector();

int nbClients = 0;





// Déclaration des méthodes



/** Constructeur de la classe Serveur */

public Server()

{

}



/** Méthode permettant d'introduire le numéro de port du serveur */

private void setListenPort(int _listenPort)

{

this.listenPort = _listenPort ;

}



/** Méthode permettant de retourner le numéro de port du serveur */

public int getPort()

{

return listenPort ;

}



/** Méthode permettant de lancer le serveur

* @throws IOException */

private void launch() throws IOException

{



// 1. Créer la socket du serveur : ServerSocket(int _port)

//int _port = getPort() ;

ss = new ServerSocket (listenPort);



System.out.println("Serveur en execution...");



try

{

while(true)

{



// 2. Appeler la méthode 'accept()' du ServerSocket créée en 1.

_s = ss.accept ();



// 3. Ajouter la nouvelle connexion dans un vecteur (ou tableau) contenant toutes les connexions

nbClients++ ;

clients.addElement(_s) ; // ou clients.add(_s)



// 4. Appeler la méthode _t.start() permettant de lancer run() (run() : permet de traiter les connexions des clients)

_t = new Thread(this);

_t.start();

}

}



catch(Exception e)

{

System.out.println("Erreur socket ...."+e);

System.exit(0);

}

}



public void run()

{

try

{

// 1. Retirer la dernière socket du vecteur

Socket sck=(Socket)clients.lastElement();



// 2. Récupérer le flux d'entrée de la socket (méthode getInputStream() de la classe Socket)

InputStream is = sck.getInputStream ();

ObjectInputStream ois = new ObjectInputStream (is);

Object obj;



// 3. Lire le premier message envoyé par le client (méthode bloquante, par exemple : readObject()), il s'agit du login de l'utilisateur

obj = ois.readObject();

logins[nbClients-1]=(String) obj;



// 4. Imprimer le message

System.out.println(logins[nbClients-1]);





// 5. Lire le message envoyé par le client (méthode bloquante)

do
{
//InputStream is2 = sck.getInputStream ();

//ObjectInputStream ois2 = new ObjectInputStream (is2);
Object obj2 = ois.readObject();

String msg=(String) obj2;



// 6. Imprimer le message

System.out.println(msg);
ois.close();
//System.out.println("Salut ca va ??);



// 7. Envoyer le message lu à tous les autres clients, le précéder par le login de l'utilisateur concerné

// Utilisation de getOutputStream() et writeObject.

msg = logins[nbClients-1] + " : " + msg;
System.out.println(nbClients);

for (int i=0 ; i<nbClients ; i++)

{

Socket sck1=(Socket)clients.elementAt(i);

OutputStream os = sck1.getOutputStream ();

ObjectOutputStream oos = new ObjectOutputStream (os);

if (!sck1.equals(sck))

{

obj = (Object) msg;

oos.writeObject(obj);

msg = (String) obj;

oos.writeObject(msg);

}
sck1.close();

}



}
while(true);





}

catch(Exception e){}

}







//////////////////////////////////////////////////////////////////////////////////////////////

// Méthode principale : 'main'

//

// Le programme prendra 1 parametre : le numero de port à surveiller

//

//////////////////////////////////////////////////////////////////////////////////////////////





public static void main(String arg[]) throws IOException

{

Server server = new Server();

int port =9999 /*Integer.parseInt (arg[0])*/;

server.setListenPort(port);

server.launch();

}



}




Et Client.java
/*

**** Chat multiclient - M1I 2008 *****

* Client.java

*

*/



// Packages à inclure

import java.net.*;

import java.io.*;





public class Client implements Runnable
{



// Déclaration des attributs de la classe



private int port ;

private String host;

private InetAddress inetAddress ;

Thread t ;

Socket s ;

String login ;



// Déclaration des méthodes



/** Constructeur de la classe Client */



public Client (/*int port*/) //throws IOException

{

//port=getPort();

//s = new Socket (host,port);

}





/** Méthode déclenchée après appel de 't.start()', son rôle consiste à lire et afficher les messages envoyés par le serveur*/

//Il s'agit principalement des messages envoyés par les autres utilisateurs (clients) */



public void run()
{

try
{

while(true)
{

// 1. Récupérer le flux d'entrée de la socket s (méthode getInputStream() de la classe Socket)

InputStream is = s.getInputStream ();

ObjectInputStream ois = new ObjectInputStream (is);

//obj = (Object) msg ;

// 2. Lire le message envoyé par le serveur (méthode bloquante, par exemple : readObject())

Object obj = ois.readObject();

// 3. Convertir l'objet ('Object') reçu en une chaine de caractères ('String')

String msg = (String) obj;

// 4. Afficher la chaine de caractères

System.out.println(msg);

}

}
catch(Exception e)

{

System.out.println(e);

}

}




/** Méthode permettant de lire une chaine de caractères depuis la ligne de commandes */

public String readMessage()throws IOException
{

String s="";

char c;

while ((c=(char)System.in.read())!='\n')

s=s+c;

return s;

}



/** Méthode permettant de se connecter au serveur, de lire les chaines de caractères depuis une ligne de commandes et de les envoyer au serveur. La chaine 'Bye' doit mettre fin à la connexion*/

public void launch()
{

try
{

String msg;

// 1. Créer la socket

System.out.println("Connexion au serveur...");

s = new Socket(getInetAddress(),getPort());



// 2. Lancer le Thread (méthode 'start') permettant de recevoir les réponses du serveur

t = new Thread(this);

t.start();

OutputStream os ;

ObjectOutputStream oos ;

os = s.getOutputStream();

oos = new ObjectOutputStream(os);

oos.writeObject(login);



// 3. Récupérer le flux de sortie de la socket (méthode getOutputStream() de la classe Socket)

do
{
//OutputStream os = s.getOutputStream();

//ObjectOutputStream oos = new ObjectOutputStream(os);

//String msg = "Message du Client";

msg=Lire.S();
System.out.println("Réception des messages en cours... \n");

//Object obj=(Object) msg;

// 4. Ecrire le message sur le flux de sortie de la socket (méthode writeObject());
oos.writeObject(msg);
}
// 5. Mettre fin à la connexion si le message envoyé est 'Bye'
while(!msg.equals("Bye"));
s.close();
System.out.println("Vous êtes deconnecté du serveur");



}


catch(IOException e)
{

System.out.println("Erreur de sérialisation "+e);

}

}



/** Méthode permettant d'introduire le numéro de port surveillé par le serveur */

public void setPort(int p)
{

if(p >0)

{

port=p;

}

}



/** Méthode permettant de retourner le numéro de port du serveur */

public int getPort()
{

return port;

}




/** Méthode permettant de retourner l'adresse IP du serveur */

public InetAddress getInetAddress()
{

return this.inetAddress;//this->pour une variable globale qui aurait le même nom que le paramètre (ici on peut ne pas le mettre)

}




/** Méthode permettant d'introduire le nom ou l'IP du serveur

* @throws UnknownHostException */

public void setInetAddress (String machineName/*InetAddress inetAddress*/) throws UnknownHostException
{

// 'if(inetAddress!='NULL')

// {

try

{

inetAddress=InetAddress.getByName(machineName);

}

catch(Exception e)

{



}

//inetAddress=InetAddress.getLocalHost(); //récupérer l'adresse IP de la machine

// }

}




/** Méthode permettant d'introduire le login de l'utilisateur */



public void getLogin() throws IOException {

System.out.print("Entrer votre login SVP : ");

this.login=readMessage();

}



public void setLogin(String _login){

this.login=_login;

}






//////////////////////////////////////////////////////////////////////////////////////////////

// Méthode principale : 'main'

//

// Le programme prendra 2 paramètres : une adresse ou un nom de serveur, un numéro de port.

//

//////////////////////////////////////////////////////////////////////////////////////////////



public static void main(String[] arg) throws UnknownHostException, IOException
{

Client em = new Client();

em.setInetAddress("localhost");

em.setPort(9999);

em.getLogin();

em.launch();

}




}



Désolé pour la longueur.


Merci d'avance pour votre aide.
0
kirua12 Messages postés 1155 Date d'inscription samedi 17 janvier 2004 Statut Membre Dernière intervention 29 avril 2011 7
24 nov. 2009 à 09:47
Salut,

c'est normal. Tu fermes le flux du client donc quand tu essaies d'écrire, tu as une erreur ce qui oblige le client à se reconnecter pour envoyer un second message.
Pourquoi fermes tu le flux ? il y a une raison particulière ?
0
cs_romain117 Messages postés 53 Date d'inscription lundi 29 juin 2009 Statut Membre Dernière intervention 21 juillet 2013 1
24 nov. 2009 à 22:45
Salut ! Merci pour ta réponse. En effet une des erreurs était bien que je fermais le flux (erreur d'inattention sans doute).
Maintenant j'y suis presque : si il y a 2 clients et que le 1er envoie un message, il faut attendre que le 2ème réponde pour que le message du premier s'affiche ! Et il faut que le 1er réponde au second pour que le message du second s'affiche ! (C'est clair ??)
Je pars du principe que lorsqu'un message est envoyé le serveur le renvoie à TOUS les clients.

Voici ce que j'ai modifié dans Serveur.java :
	// 5. Lire le message envoyé par le client (méthode bloquante)			

do
{
for (int i=0 ; i<nbClients ; i++)
{
Socket sck1=(Socket)clients.elementAt(i);
InputStream is2 = sck1.getInputStream ();
ObjectInputStream ois2 = new ObjectInputStream (is2);
Object obj2 = ois2.readObject();
String msg=(String) obj2;

// 6. Imprimer le message
msg = logins[i] + " : " + msg;
System.out.println(msg);
//System.out.println("Salut ca va ??");


// 7. Envoyer le message lu à tous les autres clients, le précéder par le login de l'utilisateur concerné
// Utilisation de getOutputStream() et writeObject.
//System.out.println(nbClients);
for (int j=0 ; j<nbClients ; j++)
{
Socket sck2=(Socket)clients.elementAt(j);
OutputStream os = sck2.getOutputStream ();
ObjectOutputStream oos = new ObjectOutputStream (os);
//if (!sck2.equals(sck1))
//{
Object obj3 = (Object) msg;
oos.writeObject(obj3);
//}
}
}
 
}
while(true);



Merci encore et toujours pour votre aide ô combien précieuse .
0
Rejoignez-nous