Exemple d'application client/serveur, comment instaurer un "dialogue" ?

Le
Francois
Bonjour à tous,

Je suis en train d'apprendre à faire une petite application
client/serveur en ligne de commande toute bête.

On lance le serveur qui est une sorte de madame Soleil,
c'est-à-dire qu'elle va afficher une prédiction au client.
Autrement dit, une fois que le serveur tourne, quand je
lance un client, une prédiction envoyée par le serveur
s'affiche sur la console du client (la prédiction est une
chaine choisie au hasard dans une liste de chaines).

Voici le code :


//--le client -
import java.io.*;
import java.net.*;

public class Client {

public void go() {
try {
Socket s = new Socket("127.0.0.1", 4242);
InputStreamReader isr = new
InputStreamReader(s.getInputStream());
BufferedReader lecture = new BufferedReader(isr);
String prediction = lecture.readLine();
System.out.println("La prédiction est : " +
prediction);
lecture.close();

} catch(IOException ex) {
System.out.println("Désolé, pas de connexion
possible");
}
}

public static void main(String[] args) {
Client client = new Client();
client.go();
}
}
//--

et le serveur

// le serveur-
import java.io.*;
import java.net.*;

public class MadameSoleilServeur {

String[] listePredictions = {"Vous êtes un homme.",
"Vous êtes une femme.",
"Vous êtes riche." };

public String getPrediction() {
int random = (int) (Math.random() *
listePredictions.length);
return listePredictions[random];
}

public void go() {
try {
ServerSocket serverSock = new ServerSocket(4242);
while(true) {
Socket sock = serverSock.accept();
String prediction = this.getPrediction();
PrintWriter ecriture = new
PrintWriter(sock.getOutputStream());
ecriture.println(prediction);
ecriture.close();
System.out.println("Envoie du message : " +
prediction);
}
} catch(IOException ex) {
System.out.println("Désolé, pas de connexion
possible");
}
}

public static void main(String[] args) {
MadameSoleilServeur serveur = new
MadameSoleilServeur();
serveur.go();
}
}
//


Le code fonctionne mais je coince sur ceci : comment faire
pour qu'il y ait un "vrai dialogue" entre le client et le
serveur ? Je veux dire par là que dans mon exemple
finalement pas de vrai dialogue : le client se connecte au
serveur et le serveur envoie sa prédiction. Par exemple,
j'aimerais qu'il soit proposé au client "Cette prédiction
vous convient-elle, oui ou non ?" et que si la réponse est
"non" le serveur renvoie une prédiction, jusqu'à ce que le
client dise "oui". Mais je ne sais pas comment faire.
Comment dire au serveur "une fois que tu as envoyé ta
prédiction, attends la réponse du client" etc
Je pense qu'il doit me manquer des connaissances, si je
pouvais avoir quelques pistes ce serait bien. Mon exemple
est bien sûr sans intérêt, c'est juste pour comprendre un
peu le principe d'une application client/serveur.

Merci pour votre aide.


--
François Lafont
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Xavier Nayrac
Le #19743541
Francois a écrit :
Je pense qu'il doit me manquer des connaissances, si je pouvais avoir
quelques pistes ce serait bien.



Tu devrais trouver ton bonheur par ici :
http://java.sun.com/docs/books/tutorial/networking/sockets/index.html

Et plus généralement :
http://java.sun.com/docs/books/tutorial/networking/index.html

--
Xavier Nayrac
http://personalbugtracker.free.fr
Francois
Le #19745211
Xavier Nayrac a écrit :

Tu devrais trouver ton bonheur par ici :
http://java.sun.com/docs/books/tutorial/networking/sockets/index.html



Merci ça m'a aidé effectivement, notamment l'exemple complet
du client.

Mais je ne comprends pas cette phrase dans cette page :
http://java.sun.com/docs/books/tutorial/networking/sockets/clientServer.html

Je cite : « When a connection is requested and successfully
established, the accept method returns a new Socket object
which is bound to the *same local port* and has it's remote
address and remote port set to that of the client. »

Je ne comprends pas "the same local port". Je croyais au
contraire que la méthode "accept" renvoyait un objet socket
sur un port *différent* du ServerSocket d'écoute pour que
justement le ServerSocket puisse continuer à faire son
travail d'écoute ? Ou alors mon anglais (assez pauvre) me
joue des tours.

Du coup, j'ai fait ceci :

//-----------------------------------
import java.net.*;

public class MadameSoleilServeur {

String[] listePredictions = {"Vous êtes un homme.",
"Vous êtes une femme.",
"Vous êtes riche." };

public String getPrediction() {
int random = (int) (Math.random() *
listePredictions.length);
return listePredictions[random];
}

public void go() throws IOException {

ServerSocket serverSock = null;
Socket connexionSock = null;
PrintWriter out = null;
BufferedReader in = null;
String reponseClient = null;
String prediction = null;

try {
serverSock = new ServerSocket(4242);
while(true) {
connexionSock = serverSock.accept();
out = new
PrintWriter(connexionSock.getOutputStream(), true);
in = new BufferedReader(new
InputStreamReader(connexionSock.getInputStream()));
reponseClient = in.readLine();
while(!reponseClient.equals("non")) {
prediction = this.getPrediction();
out.println(prediction);
reponseClient = in.readLine();
}
}
} catch(IOException ex) {
System.out.println("Désolé, pas de connexion
possible...");
System.exit(-1);
}
}

public static void main(String[] args) throws IOException {
MadameSoleilServeur serv = new MadameSoleilServeur();
serv.go();
}

}
//-----------------------------------

et

//-----------------------------------
import java.io.*;
import java.net.*;

public class Client {

public static void main(String[] args) throws IOException {

Socket clientSocket = null;
PrintWriter out = null;
BufferedReader in = null;

try {
clientSocket = new Socket("127.0.0.1", 4242);
out = new
PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new
InputStreamReader(clientSocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Impossible de contacter le
serveur.");
System.exit(1);
} catch (IOException e) {
System.err.println("Impossible d'obtenir I/O
venant du serveur.");
System.exit(1);
}

BufferedReader stdIn = new BufferedReader(new
InputStreamReader(System.in));
System.out.print("Voulez vous une prédiction, oui
ou non ? ");
String userInput = stdIn.readLine();
out.println(userInput);
while (!userInput.equals("non")) {
System.out.println("Voici la prédiction : " +
in.readLine());
System.out.print("Encore une autre, oui ou non ? ");
userInput = stdIn.readLine();
out.println(userInput);
}

out.close();
in.close();
stdIn.close();
clientSocket.close();

}
}
//-----------------------------------

Je trouve que ce n'est pas facile ce couplage entre le
client et le serveur, ça rend les choses deux fois plus
compliquées : quand je code le client je dois avoir le
serveur en tête et inversement. Y a-t-il des moyens pour
faire des dialogues client/serveur avec un code plus facile
à appréhender. Peut-être des factorisations de codes, une
classe que pourraient avoir le client et le serveur en commun ?

Merci pour votre aide.


--
François Lafont
Alain Ketterlin
Le #19746381
Francois
Xavier Nayrac a écrit :

Tu devrais trouver ton bonheur par ici :
http://java.sun.com/docs/books/tutorial/networking/sockets/index.html





[...]
Je cite : « When a connection is requested and successfully
established, the accept method returns a new Socket object which is
bound to the *same local port* and has it's remote address and remote
port set to that of the client. »

Je ne comprends pas "the same local port". Je croyais au contraire que
la méthode "accept" renvoyait un objet socket sur un port *diffà ©rent*
du ServerSocket d'écoute pour que justement le ServerSocket puisse
continuer à faire son travail d'écoute ? Ou alors mon anglais ( assez
pauvre) me joue des tours.



Tu confonds port et socket. La socket de communication (renvoyée par
accept) est bien liée au même port local, mais elle est identifi ée par
les deux extrémités. Localement, il semble donc bien y avoir plus ieurs
sockets liées au même port, mais elles sont bien distinguées (par
l'adresse et le port du correspondant dans le cas des socket de comm).
Et le ServerSocket peut continuer à faire son boulot (il n'a pas de
correspondant, lui).

[...]
serverSock = new ServerSocket(4242);
while(true) {
connexionSock = serverSock.accept();
out = new PrintWriter(connexionSock.getOutputStream(),
true);
in = new BufferedReader(new
InputStreamReader(connexionSock.getInputStream()));
reponseClient = in.readLine();
while(!reponseClient.equals("non")) {
prediction = this.getPrediction();
out.println(prediction);
reponseClient = in.readLine();
}



Ce n'est pas la bonne stratégie, parce que tu n'écoutes pas la
ServerSocket pendant que tu réponds à un client, alors qu'il peut y
avoir plusieurs demandes de connexion pendant ce temps. Tout cela est
expliqué dans le document évoqué ci-dessus, malheureusement tout à la
fin de la dernière section. Imagine que :

- l'objet ServerSocket sert uniquement à distribuer des Socket (c'est le
standard téléphonique, si tu veux)
- chaque Socket est un canal entre le serveur et un client (c'est une
ligne ouverte)

Le Serveur est donc en général découpé en N+1 threads : un thread de
distribution de Socket (c'est lui qui fait accept() sans arrêt), et N
threads, chacun connecté avec un client différent.

(Note aussi que tout cela n'est pas spécifique à Java, c'est le
fonctionnement normal des sockets TCP. Quand ce n'est pas du Java, il
arrive qu'on utilise des processus plutôt que des threads.)

-- Alain.
Publicité
Poster une réponse
Anonyme