Partage
  • Partager sur Facebook
  • Partager sur Twitter

Fermer un socket proprement

Bug lors d'une déconnection d'un joueur

    24 octobre 2022 à 17:40:28

    Bonjour à tous,

    Je suis entrain de développer un petit jeu qui fonctionne en réseau mais j'ai un petit problème. Le réseau marche en TCP et fonctionne avec des thread. Je peux lancer le serveur qui communique bien entre lui et le client (Je lance mon PPTI qui est mon réseau puis l'IDJR le joueur. Je vérifie si le Client veut bien rejoindre le serveur. Je l'accepte tout fonctionne jusqu'à pour l'instant). Cependant c'est quand un joueur quitte la partie (exemple : si je ferme la console concernant le joueur), il fait planter le ClientHandler.

    Ce que j'aimerai faire c'est de créer une exception dans le ClienHandler qui quand un joueur quitte le serveur, il ne fasse pas tout planter et qu'un message soit adressé au autre pour dire que telle joueur a quitté le serveur.

    Voici mon code pour l'instant : 

    ClientHandler :

    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.net.Socket;
    import java.util.Scanner;
    
    public class ClientHandler extends Thread {
    
        static DataInputStream in;
        static DataOutputStream out;
        static Socket sock;
        static String name = "PPTI";
    
        public ClientHandler(Socket sock, DataInputStream in, DataOutputStream out) {
            this.sock = sock;
            this.in = in;
            this.out = out;
        }
    
        @Override
        public void run() {
            String received;
            String toreturn;
            while (true) {
                try {
                    received = in.readUTF();
                    System.out.println(received);
                    Scanner scan = new Scanner(System.in);
                    String repServer = scan.next();
    
                    if (repServer.equals("Yes")) {
                        out.writeUTF(name + ": ADP-IDP-IDJ");
                    } else if (repServer.equals("No")) {
                        out.writeUTF(name + ":RDP-IDP");
                    } else {
                        System.out.println("Invalid input");
                    }
    
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    Je ne pense pas que mes autres classe réseau soit utiles mais les voici si besoins :

    IDJR : 

    import java.io.*;
    import java.net.*;
    import java.nio.charset.StandardCharsets;
    import java.util.Enumeration;
    
    
    public class IDJR {
        static String name = "IDJR";
        static InetAddress addr;
        static int port = 7777;
        static MulticastSocket group;
        static String eth;
        static String HOST = "localhost";
        static DataInputStream in;
        static DataOutputStream out;
        static Socket sc = null;
        static String test;
    
        public void joinTcpServer(String host , int port) throws IOException {
            sc = new Socket(host, port);
        }
    
        public void sendTcpMessage(String message) throws IOException {
            out = new DataOutputStream(sc.getOutputStream());
            out.writeUTF(name + ": " + message);
        }
    
        public void receiveTcpMessage() throws IOException {
            in = new DataInputStream(sc.getInputStream());
            while (true) {
                System.out.println(in.readUTF());
            }
    
        }
        public void joinUdpServer(String ip, int port) {
            System.setProperty("java.net.preferIPv4Stack","true");
            if (group != null) {
                group.close();
            }
            try {
                Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
                while (interfaces.hasMoreElements()) {
                    NetworkInterface ni = interfaces.nextElement();
                    if (ni.isUp()) {
                        String niTexte = ni.getDisplayName();
                        if (niTexte.contains("Intel(R)") || niTexte.contains("eno") || niTexte.contains("Wireless")) {
                            eth = ni.getName();
                        }
                    }
    
                }
                group = new MulticastSocket (port);
                addr = InetAddress.getByName(ip);
                group.setNetworkInterface(NetworkInterface.getByName(eth));
                System.out.println(group.getNetworkInterface());
    
    
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            Thread threadUdp = new ThreadClient(name,addr,port,group);
            threadUdp.start();
        }
    
        public void sendUdpMessage(String message){
            try {
                String msg = name + ": " + message ;
                byte[] out = msg.getBytes(StandardCharsets.UTF_8);
                DatagramPacket pkt = new DatagramPacket(out, out.length, addr, port);
                group.send(pkt);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        static class ThreadClient extends Thread {
            static String name;
            static InetAddress addr;
            static int port;
            static MulticastSocket group;
    
            public ThreadClient(String name, InetAddress addr, int port, MulticastSocket group) {
                this.name = name;
                this.addr = addr;
                this.port = port;
                this.group = group;
            }
    
            public void sendUdpMessage(String message) {
                try {
                    String msg = name + ": " + message;
                    byte[] out = msg.getBytes(StandardCharsets.UTF_8);
                    DatagramPacket pkt = new DatagramPacket(out, out.length, addr, port);
                    group.send(pkt);
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            public void run() {
    
                try {
                    int cpt = 0;
                    byte[] in = new byte[1024];
                    DatagramPacket pkt = new DatagramPacket(in, in.length);
                    group.joinGroup(addr);
                    while (cpt != 2) {
                        group.receive(pkt);
                        String s = new String(pkt.getData(), 0, pkt.getLength(), StandardCharsets.UTF_8);
                        System.out.println(s);
                        cpt++;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            }
        }
    
        public static void main(String[] args) throws IOException {
    
            //Partie UDP
            IDJR idjr = new IDJR();
            String message = "RUP-TYPEP-TAILLEP";
            String messageV1 = "DCP-NOM-TYPE-IDP";
            idjr.joinUdpServer("224.7.7.7", 7777);
            idjr.sendUdpMessage(message);
            idjr.joinTcpServer("localhost",7777);
            idjr.sendTcpMessage(messageV1);
            idjr.receiveTcpMessage();
    
        }
    }
    

    PPTI :

    import java.io.*;
    import java.net.*;
    import java.nio.charset.StandardCharsets;
    import java.util.*;
    
    public class PPTI {
        static String name = "PPTI";
        static InetAddress addr;
        static int port = 7777;
        static MulticastSocket group;
        static String eth;
        static ServerSocket serv = null;
        static Socket sc = null;
        static DataInputStream in;
        static DataOutputStream out;
    
    
        public void joinTcpServer(int port) throws IOException {
            try {
                serv = new ServerSocket(port);
                while (true){
                    sc = serv.accept();
                    in = new DataInputStream(sc.getInputStream());
                    out = new DataOutputStream(sc.getOutputStream());
    
                    Thread t = new ClientHandler(sc, in, out);
                    t.start();
                }
            } catch (IOException e) {
                sc.close();
                throw new RuntimeException(e);
            }
        }
        public void joinUdpServer(String ip, int port) {
            System.setProperty("java.net.preferIPv4Stack","true");
            if (group != null) {
                group.close();
            }
            try {
                Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
                while (interfaces.hasMoreElements()) {
                    NetworkInterface ni = interfaces.nextElement();
                    if (ni.isUp()) {
                        String niTexte = ni.getDisplayName();
                        if (niTexte.contains("Intel(R)") ||niTexte.contains("eno") || niTexte.contains("Wireless")) {
                            eth = ni.getName();
                        }
                    }
    
                }
                group = new MulticastSocket (port);
                addr = InetAddress.getByName(ip);
                group.setNetworkInterface(NetworkInterface.getByName(eth));
                System.out.println(group.getNetworkInterface());
    
    
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            Thread threadUdp = new ThreadServer(name,addr,port,group);
            threadUdp.start();
        }
    
    
        public void sendUdpMessage(String message){
            try {
                String msg = name + ": " + message ;
                byte[] out = msg.getBytes(StandardCharsets.UTF_8);
                DatagramPacket pkt = new DatagramPacket(out, out.length, addr, port );
                group.send(pkt);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
           static class ThreadServer extends Thread{
            static String name ;
            static InetAddress addr;
            static int port ;
            static MulticastSocket group;
            String updateMessage = "AMP-IDP-IP-PORT-NOM-TYPEP-NBJ-NBJRM-NBJVM-ESPA-STATUT";
    
            public ThreadServer(String name, InetAddress addr ,int port , MulticastSocket group){
                this.name = name;
                this.addr = addr;
                this.port = port;
                this.group = group;
            }
    
            public void sendUdpMessage(String message){
                try {
                    String msg = name + ": " + message ;
                    byte[] out = msg.getBytes(StandardCharsets.UTF_8);
                    DatagramPacket pkt = new DatagramPacket(out, out.length, addr, port);
                    group.send(pkt);
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            public void run() {
    
                try {
                    byte[] in = new byte[1024];
                    DatagramPacket pkt = new DatagramPacket(in, in.length);
                    group.joinGroup(addr);
                    while (true) {
                        group.receive(pkt);
                        String s = new String(pkt.getData(),0, pkt.getLength(),StandardCharsets.UTF_8);
                        System.out.println(s);
                        if(s.contains("RUP")){
                            sendUdpMessage(updateMessage);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            }
    
        }
    
    
        public static void main(String[] args) throws IOException {
    
            //Partie UDP
            PPTI pptitest = new PPTI();
            String message = "ACP-IDP-IP-PORT-NOM-TYPEP-NBJ-NBJRM-NBJVM-ESPA-STATUT";
            pptitest.joinUdpServer("224.7.7.7", 7777);
            pptitest.sendUdpMessage(message);
            pptitest.joinTcpServer(port);
        }
    
    }
    





    • Partager sur Facebook
    • Partager sur Twitter
      16 novembre 2022 à 22:48:26

      Bonjour,

      Si j’ai bien lu ton code, tu lis en boucle ce que tu reçois, donc à chaque fois ton serveur est en attente d’un message du client. Si la connexion est coupée alors qu’il attendait une réponse du client, il va générer une exception (Socket close potentiellement).

      Mais du coup je ne comprend pas trop ta question ? Tu récupères l’exception dans ton catch ligne 38 pour ensuite renvoyer un RuntimeException, mais c’est justement à cet endroit au lieu de renvoyer un RuntimeException que tu devrais faire le nécessaire pour gérer la déconnexion du client si je ne me trompe pas ?

      Bonne soirée,

      • Partager sur Facebook
      • Partager sur Twitter
        31 décembre 2022 à 14:54:38

        vous pouvez essayer d'intercepter l'exception IOException qui se produit lorsque le client se déconnecte du serveur. Vous pouvez le faire en utilisant un try-catchdans votre code de gestionnaire de client, comme ceci:
        try {
            // Code de gestion du client qui peut générer une IOException
        } catch (IOException e) {
            // Code pour gérer l'exception et envoyer un message au autre joueur
        }
        

        Vous pouvez utiliser la méthode writeObject() de l'objet ObjectOutputStream associé au autre joueur pour envoyer un message indiquant que le joueur a quitté le serveur. Assurez-vous également de fermer les flux de données et la socket associée au joueur déconnecté pour libérer les ressources.

        Il est également recommandé de mettre en place une boucle de lecture de données qui s'arrête lorsque le client se déconnecte, plutôt que de lire les données du client de manière bloquante. Cela vous permettra de détecter plus rapidement la déconnexion du client et de gérer l'exception plus efficacement.

        Voici un exemple de code de gestionnaire de client qui utilise une boucle de lecture de données et intercepare l'exception IOException:

        while (true) {
            try {
                // Lire les données du client
                Object data = inputStream.readObject();
                // Traiter les données reçues
                // ...
            } catch (IOException e) {
                // Gérer l'exception et envoyer un message au autre joueur
                break;
            }
        }
        
        // Fermer les flux de données et la socket associée au joueur déconnecté
        inputStream.close();
        outputStream.close();
        clientSocket.close();
        

        Voici comment votre code pourrait être modifié en utilisant les conseils que je vous ai donnés:

        import java.io.DataInputStream;
        import java.io.DataOutputStream;
        import java.io.IOException;
        import java.net.Socket;
        import java.util.Scanner;
        
        public class ClientHandler extends Thread {
        
            static DataInputStream in;
            static DataOutputStream out;
            static Socket sock;
            static String name = "PPTI";
        
            public ClientHandler(Socket sock, DataInputStream in, DataOutputStream out) {
                this.sock = sock;
                this.in = in;
                this.out = out;
            }
        
            @Override
            public void run() {
                while (true) {
                    try {
                        // Lire les données du client
                        String received = in.readUTF();
                        System.out.println(received);
                        Scanner scan = new Scanner(System.in);
                        String repServer = scan.next();
        
                        if (repServer.equals("Yes")) {
                            out.writeUTF(name + ": ADP-IDP-IDJ");
                        } else if (repServer.equals("No")) {
                            out.writeUTF(name + ":RDP-IDP");
                        } else {
                            System.out.println("Invalid input");
                        }
                    } catch (IOException e) {
                        // Gérer l'exception et envoyer un message au autre joueur
                        break;
                    }
                }
        
                // Fermer les flux de données et la socket associée au joueur déconnecté
                try {
                    in.close();
                    out.close();
                    sock.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        
        • J'ai remplacé l'instruction throw new RuntimeException(e); par une boucle break pour intercepter l'exception IOException et sortir de la boucle de lecture de données.
        • J'ai ajouté des instructions try-catch pour fermer les flux de données et la socket associée au joueur déconnecté lorsque l'exception est interceptée.
        • J'ai enlevé les déclarations static des variables in, out et sock pour éviter de partager ces ressources entre tous les objets de type ClientHandler.

        -
        Edité par AdrianaPetrovski 31 décembre 2022 à 14:57:53

        • Partager sur Facebook
        • Partager sur Twitter

        Fermer un socket proprement

        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
        • Editeur
        • Markdown