Besoin d'aide sur une application Client/Serveur [Résolu]

Lapigus - 3 déc. 2017 à 18:45 - Dernière réponse :  Lapigus
- 3 déc. 2017 à 22:25
Bonjour,

Je cherche à faire une application très simple (vraiment simple) Client-Serveur en mode TCP sur java et ce que je veux c'est d'envoyer une trame contenant un String du client au serveur puis de renvoyer une autre trame String du serveur au client. Le premier mesage "How are you" arrive bien au serveur et l'affiche dans sa console appropriée, le serveur envoie la réponse mais impossible d'intercepter la réponse côté client. C'est apparemment dû à un problème de reset mais je ne comprends pas...

Merci d'avance pour votre aide :)

Voici le code le avec le message d'erreur dans la console client_tcp :

import java.io.*;
import java.net.*;

public class Server_tcp {
public static void main(String[] args) throws IOException {
ServerSocket server_socket = new ServerSocket(1026);

//interception du message
Socket s = server_socket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
System.out.println(in.readLine());
System.out.println("client address :"+s.getInetAddress()+" on "+s.getPort());
in.close();

//création de la réponse
Socket socket2 = new Socket(s.getInetAddress(),1026);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket2.getOutputStream()));
String res = "I'm fine";
out.write(res);
out.close();

//fermeture des sockets
s.close();
socket2.close();
server_socket.close();
}

}

import java.io.*;
import java.net.*;

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

//création du message à envoyer
Socket client_socket = new Socket("localhost",1026);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client_socket.getOutputStream()));
String msg = "How are you ?";
out.write(msg);
out.close();

//interception de la réponse
Socket socket2 = new Socket(InetAddress.getLocalHost(),1026);
BufferedReader in = new BufferedReader(new InputStreamReader(socket2.getInputStream()));
System.out.println(in.readLine());
in.close();

//fermeture de la connexion
client_socket.close();
socket2.close();

}

}


La console côté client :
Exception in thread "main" java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:210)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at Client_tcp.main(Client_tcp.java:17)
Afficher la suite 

4 réponses

Répondre au sujet
KX 15081 Messages postés samedi 31 mai 2008Date d'inscriptionModérateurStatut 10 décembre 2017 Dernière intervention - 3 déc. 2017 à 19:45
+1
Utile
3
Bonjour,

Le problème c'est que le port doit être ouvert côté serveur avant que le client n'essaie de se connecter dessus.

Or ici au moment où ton client devient serveur et où ton serveur devient client il y a un conflit, notamment parce que le serveur n'a pas fermé sa première connexion.

Le mieux serait d'utiliser deux ports, un dédié à chaque programme qu'ils démarreront en tant que serveur.

Remarque : du coup ça n'a plus trop de sens que le premier programme s'appelle Serveur et le deuxième Client, car en fait ils ont tous le double rôle.
Wow merci ! J'ai finalement réussi grâce à toi :)
Du coup j'ai utilisé la méthode de la classe ServerSocket dans le programme client alors qu'elle était pour moi strictement réservée au programme serveur.

Il n'empêche que je ne saisi pas pourquoi je devais aussi utiliser un autre numéro de port (pour le deuxième message) en essayant de fermer la première connexion par la méthode socket.close() glissé, bien entendu, au dessus de la partie du programme où je crée la réponse.

La connexion ne se ferme que lorsque le programme entier a fini de s'exécuter ?

Si jamais quelqu'un a une idée !
KX 15081 Messages postés samedi 31 mai 2008Date d'inscriptionModérateurStatut 10 décembre 2017 Dernière intervention > Lapigus - 3 déc. 2017 à 21:52
"La connexion ne se ferme que lorsque le programme entier a fini de s'exécuter ?"
La connexion se ferme quand tu le demandes côté "serveur", cependant le "client" ne peut pas savoir à quel moment cela se produit et donc quand il peut réutiliser le port, c'est pour ça qu'il vaut mieux utiliser un deuxième port, dont le "client" sera sûr qu'il est disponible à tout moment puisqu'il est le seul à l'utiliser, la connexion du "serveur" peut donc être fermée n'importe quand, ça n'empêchera pas le "client" de fonctionner.

Remarque : dans un cas d'usage plus complexe, où tu échangerais plusieurs messages de l'un vers l'autre, c'est clairement la solution à deux ports qui fonctionne le mieux, parce que ça te permet de garder les deux connexions ouvertes en même temps (full-duplex) et d'échanger autant de messages que tu veux dans un sens ou dans l'autre sans avoir à ouvrir et fermer des connexions à chaque fois (half-duplex).

Exemple :

import java.io.*;
import java.net.*;

public class FullDuplex implements AutoCloseable {

    private final BufferedReader in;
    private final BufferedWriter out;

    public FullDuplex(String host, int serverPort, int clientPort, long connectDelay) throws IOException {
        ServerSocket acceptSocket = new ServerSocket(serverPort);
        Socket serverSocket, clientSocket;
        try {
            clientSocket = new Socket(host, clientPort);
            serverSocket = acceptSocket.accept();
        } catch (ConnectException e) {
            serverSocket = acceptSocket.accept();
            clientSocket = new Socket(host, clientPort);
        }
        acceptSocket.close();
        in = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
        out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
    }

    public String readLine() throws IOException {
        String line = in.readLine();
        System.err.println("Server << " + line);
        return line;
    }

    public void writeLine(String line) throws IOException {
        System.err.println("Client >> " + line);
        out.write(line);
        out.newLine();
        out.flush();
    }

    @Override
    public void close() throws IOException {
        out.close();
        in.close();
    }
}

public static void main(String[] args) throws IOException {
    FullDuplex common = new FullDuplex("localhost", 1026, 1027, 500);
    common.writeLine("What's your name ?");
    String name = common.readLine();
    common.writeLine("Hello " + name + " !");
    common.close();
}

public static void main(String[] args) throws IOException {
    FullDuplex common = new FullDuplex("localhost", 1027, 1026, 500);
    common.readLine();
    common.writeLine(System.getProperty("user.name"));
    common.readLine();
    common.close();
}
Ah je comprends mieux pourquoi il faut deux ports, et c'est aussi pour éviter les collisions j'imagine ?
En tout cas merci beaucoup pour ton code, ça va me servir pour approfondir le sujet
Commenter la réponse de KX